牛客NOIP模拟第五场T1
Description
给定(l_1,r_1,l_2,r_2,m) 求(sum limits _{x=l_1}^{r_1}) (sum limits _{y=l_2}^{r_2} (xwedge y\%m=0))
- (l_1le r_1 le 10^{18},l_2le r_2le 10^{18},mle 10^9)
Solution
约定 (num(a,t)) 为01串(a) 剩余后缀长度为(t+1) 的前缀
-
性质1:对于01串 (a),(b) 取二者的后缀长度为(t_1+1),(t_2+1) , 前缀后的位置01随意构造,对于每个能异或出的数,方案数为 (2^{min (t_1,t_2)})
-
性质2:对于01串 (a),(b) 取二者的后缀长度为(t_1+1),(t_2+1) ,
(Dim:)
- $s=num(a,max(t_1,t_2)) wedge num(b,max(t_1,t_2)) $
- (xin [a<<max(t_1,t_2),a<<max(t_1,t_2)+2^{max(t_1,t_2)}-1])
- (yin [b<<max(t_1,t_2),b<<max(t_1,t_2)+2^{max(t_1,t_2)}-1])
则$ xwedge y in [s<<max(t_1,t_2),s<<max(t_1,t_2)+2^{max(t_1,t_2)}-1]$
-
根据性质2,可以算出可以取到多少种m的倍数,记为c,然后再根据性质1,方案数就为 (c imes 2^{max(t_1,t_2)})
-
利用上述性质可以在(O(count(10^{18})^2))的时间复杂度下求出 (xin [0,a] ,yin[0,b]) 的答案
-
方法是枚举 (a),(b) 为1的二进制位,把它变为0,那么后面的位置01就可以随便放,并且可以证明这样枚举出来的方案数是补充不漏的
Code
#include<cstdio>
#define FOR(i,x,y) for(int i=(x),i##_END=(y);i<=i##_END;i++)
const int P=998244353;
typedef long long LL;
int m;
LL calc(LL x){
if(x<0)return -1;
return x/m;
}
LL Solve(LL X,LL Y){
LL res=0,x,y;
FOR(i,0,60)if(X&(1ll<<i)){
FOR(j,0,60)if(Y&(1ll<<j)){
int mi=i<j?i:j,mx=i>j?i:j;
if(i>j)x=X,y=Y;
else x=Y,y=X;
x>>=mx,y>>=mx;
x^=1;
if(i==j)y^=1;
x^=y;
x<<=mx;
LL l,r;
l=calc(x-1);
r=calc(x+(1ll<<mx)-1);
res=(res+(LL)(r-l)%P*((1ll<<mi)%P))%P;
}
}
return res%P;
}
int main(){
LL l1,r1,l2,r2;
scanf("%lld%lld%lld%lld%d",&l1,&r1,&l2,&r2,&m);
printf("%lld
",((Solve(r1+1,r2+1)-Solve(r1+1,l2)-Solve(l1,r2+1)+Solve(l1,l2))%P+P)%P);
return 0;
}