卧薪尝胆,厚积薄发。
同余方程
Date: Thu Oct 11 20:10:08 CST 2018
In Category:
NoCategory
Description:
求方程
$x\text{ xor }y\equiv0\mod m$
的解数。
$x\in[l_1,r_1],y\in[l_2,r_2]$
$1\leqslant l_1,r_1,l_2,r_2\leqslant10^{18},1\leqslant m\leqslant10^9$
Solution:
首先考虑
$x\in[0,2^k),y\in[0,2^k)$
,那么
$x\text{ xor }y$
的值
$[0,2^k)$
每个数都出现了
$2^k$
次,如果
$x\in[0,2^n),$
$y\in[0,2^m),$
$(n<m)$
,那么
$x\text{ xor }y$
的值
$[0,2^m)$
每个数都出现了
$2^n$
次,两个
$w$
位二进制数
$a$
和
$b$
,如果
$a$
第
$i$
位为
$1$
,
$b$
第
$j$
位为
$1$
$(i<j)$
,那么类似数位
$DP$
就可以统计
$a[i,w][0,2^i)$
和
$b[j,w][0,2^j)$
对答案的贡献,那么这些所有的数能组合出
$\biggl[a[j,w]\text{ xor }b[j,w]\biggl][0,2^j)$
的所有数,且每个数都出现了
$2^i$
次,这样把二维区间和拆成四个二位前缀和统计即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
ll l1,r1,l2,r2,m;
#define MOD 998244353
ll query(ll l,ll r,ll m)
{
return (r / m - l / m + (l % m == 0 ? 1 : 0)) % MOD;
}
ll calc(ll x,ll y)
{
ll res = 0;
for(ll i = 0;i <= 60;++i)
{
for(ll j = 0;j <= 60;++j)
{
if(((x >> i) & 1) && ((y >> j) & 1))
{
ll high = max(i,j),low = min(i,j);
ll high_bits = ~((1ll << high) - 1);
ll high_val = ((x - (1ll << i)) & high_bits) ^ ((y - (1ll << j)) & high_bits);
res = (res + query(high_val,high_val | ((1ll << high) - 1),m) * ((1ll << min(i,j)) % MOD) % MOD) % MOD;
}
}
}
return res;
}
int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&m);
ll res = calc(r1 + 1,r2 + 1) - calc(l1,r2 + 1) - calc(r1 + 1,l2) + calc(l1,l2);
res = (res % MOD + MOD) % MOD;
printf("%lld\n",res);
fclose(stdin);
fclose(stdout);
return 0;
}
In tag:
DP-数位DP
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡