异或

也许更好的体验
(mathcal{Description})

给定L,R,求
(sum_{i=L}^{R}xorsum_{i=L}^{R})
答案对1000000007取模
(L,R<=10^9)
(mathcal{Solution})

对于有异或的题目要记住这点
每个二进制位是独立计算答案的
我们只需知道([L,R])中所有数在每个位上的情况:有多少(0)多少(1)
只有(1)^(0)的结果为(1),统计出每个为上的(1)(0)的个数,用当前位的值乘以(1)的个数再乘以(0)的个数即可
对于每个二进制位上的0和1出现情况
如第(3)
000
001
010
011
100
101
110
111
(2^4)出现(2^3)(0)(1)
不难发现每(2^{n+1})个数在第n位出现(2^n)(0)(1)
由于对数会被异或两次 i^j j^i,所以计算时要乘以(2)
(ans=(ans+2*zero[i]*one[i]*2^i)%mod;)
其中(mi[i]=2^i)
(0)(1)的计算
用一个简单的容斥即可
对于第n位
R中包含的(2^{n+1})的个数减去L中包含的(2^{n+1})个数加上(R\%2^{n+1})中的个数减去(L\%2^{n+1})中的个数
注意起点为(0),即求的区间是([0,R]-[0,L-1])
处理看代码吧

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年06月10日 星期一 07时59分11秒
*******************************/
#include <cstdio>
#include <fstream>
#include <cstring>
using namespace std;
const int mod = 1000000007;
const int maxn = 55;
int n,T,t,l,r;
long long ans;
long long zero[maxn],one[maxn],mi[maxn];
int main()
{
	scanf("%d",&T);
	mi[0]=1;
	for (int i=1;i<=31;++i)	mi[i]=mi[i-1]<<1;
	while (T--){
		scanf("%d%d",&l,&r);
		memset(one,0,sizeof(one));
		memset(zero,0,sizeof(zero));
		ans=0;
		for (int i=0;mi[i]<=r;++i){
			one[i]=((r+1)/mi[i+1]-l/mi[i+1])*mi[i];//R中包含的2^{n+1}的个数减去L中包含的2^{n+1}个数
			zero[i]=one[i];
			//加上R%2^{n+1}中的个数
			if (r+1>mi[i+1]){
				t=(r+1)%mi[i+1];
				if (t>mi[i])	one[i]+=t-mi[i],zero[i]+=mi[i];
				else	zero[i]+=t;
			}
			else if (r+1<mi[i+1]){
				if (r+1>mi[i])	one[i]+=r+1-mi[i],zero[i]+=mi[i];
				else	zero[i]-=r+1;
			}
			//减去L%2^{n+1}中的个数
			if (l>mi[i+1]){
				t=l%mi[i+1];
				if (t>mi[i])	one[i]-=t-mi[i],zero[i]-=mi[i];
				else	zero[i]-=t;
			}
			else if (l<mi[i+1]){
				if (l>mi[i])	one[i]-=l-mi[i],zero[i]-=mi[i];
				else	zero[i]-=l;
			}
			ans=(ans+2ll*zero[i]*one[i]%mod*mi[i])%mod;
		}
		printf("%lld
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Morning-Glory/p/11011334.html