位运算相关

牛客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} (x\wedge y\%m=0)\)

  • \(l_1\le r_1 \le 10^{18},l_2\le r_2\le 10^{18},m\le 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)) $
    • \(x\in [a<<max(t_1,t_2),a<<max(t_1,t_2)+2^{max(t_1,t_2)}-1]\)
    • \(y\in [b<<max(t_1,t_2),b<<max(t_1,t_2)+2^{max(t_1,t_2)}-1]\)

    则$ x\wedge 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\times 2^{max(t_1,t_2)}\)

  • 利用上述性质可以在\(O(count(10^{18})^2)\)的时间复杂度下求出 \(x\in [0,a] ,y\in[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\n",((Solve(r1+1,r2+1)-Solve(r1+1,l2)-Solve(l1,r2+1)+Solve(l1,l2))%P+P)%P);
	return 0;
}
posted @ 2018-10-15 16:47  Zerokei  阅读(105)  评论(0编辑  收藏  举报