[CSP-S模拟测试]:异或(数学)
Posted wzc521
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:异或(数学)相关的知识,希望对你有一定的参考价值。
题目描述
给定$L,R$,我们希望你求出:
$$sumlimits_{i=L}^Rsumlimits_{j=L}^R(ioplus j)$$
其中这里的$oplus$表示异或运算。
答案对$10^9+7$取模。
输入格式
第一行一个整数$T$,表示数据组数。
接下来$T$行,每行两个整数$L,R(0leqslant Lleqslant Rleqslant 10^9)$,描述一组数据。
输出格式
每组数据输出一行一个整数,表示答案。
样例
样例输入:
2
1 2
0 1023
样例输出:
6
536346624
数据范围与提示
样例解释:
第一组数据:$1oplus 1=2oplus 2=0,1oplus 2=3$。
数据范围:
对$100\%$的数据,$Tleqslant 50$。
$ullet$子任务$1$($20$分):保证$L,Rleqslant 1,000$。
$ullet$子任务$2$($30$分):保证$(R−L)leqslant 10^6$。
$ullet$子任务$3$($10$分):保证$L=0,R=2^k−1$。
$ullet$子任务$4$($40$分):无特殊限制。
题解
又没打正解,讲一下我的做法。
其实答案就是二进制位下每一位$1$的个数乘每一位$0$的个数乘$1<<$当前位数。
那么考虑如何快速求出每一位$1$和$0$的个数。
把每一个数拆成二进制位,如下$downarrow$
0:0000
1:0001
2:0010
3:0011
4:0100
5:0101
6:0110
7:0111
那么我们会惊喜的发现第$i$位会呈一个$2 imes i$的循环节,先是$i$个$0$,之后是$i$个$1$。
算出$0sim R$中$0$和$1$的个数再减去$0sim L$的即可,这样就能算出每一位$0$和$1$的个数了,也就求出了答案。
时间复杂度:$Theta(30 imes T)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long long L,R;
long long ans;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ans=0;
scanf("%lld%lld",&L,&R);
for(long long i=1;i<=30;i++)
{
long long flag=(R/(1<<i)-(L-1)/(1<<i))<<(i-1);
if(R%(1<<i)-(1<<(i-1))+1>0)flag+=R%(1<<i)-(1<<(i-1))+1;
if((L-1)%(1<<i)-(1<<(i-1))+1>0)flag-=(L-1)%(1<<i)-(1<<(i-1))+1;
ans=(ans+flag*(R-L+1-flag)%mod*(1<<i)%mod)%mod;
}
printf("%lld
",ans);
}
return 0;
}
rp++
以上是关于[CSP-S模拟测试]:异或(数学)的主要内容,如果未能解决你的问题,请参考以下文章