异或

也许更好的体验
D e s c r i p t i o n \mathcal{Description} Description

给定L,R,求

∑ i = L R x o r ∑ i = L R \sum_{i=L}^{R}xor\sum_{i=L}^{R} i=LRxori=LR

答案对1000000007取模
L , R &lt; = 1 0 9 L,R&lt;=10^9 L,R<=109
S o l u t i o n \mathcal{Solution} Solution

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

/*******************************
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\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值