问题
时限:1.5s
空间:64M
给你n≤5×107n\leq5\times10^7n≤5×107个数字,每个数字≤109\leq 10^9≤109,问你有多少对数字异或起来的值在二进制下的111的个数为奇数个。
- 暴力
这个直接O(n2)O(n^2)O(n2)枚举计算就可以了,但是是肯定不行的,所以我们要考虑其他方法。
- 观察
对于两个数字,某一位异或为111的话那么原来的两个数字的那一位必须不一样,如果异或为000的话,原来的两个数字的两位肯定一样。
所以我们发现,它某一位从原来的111变成000的话,必须是同时都为111,那么最后两个数字的111减少的个数和肯定为偶数,所以我们只需要原来的111的个数和为奇数,那么最后消除后剩下的111的个数肯定还是奇数,而只有两个数的111的个数分别为一奇一偶,加起来才为奇数个。
- 栗子如下:
110010 xor 010001=100011110010\ \mathbf{xor}\ 010001=100011110010 xor 010001=100011
原来有3+2=53+2=53+2=5个111,而其中的顺数第二位,两个数字都为111,所以消去了,剩下333个111,那么就为奇数。
11001 xor 00111=1111011001\ \mathbf{xor}\ 00111=1111011001 xor 00111=11110
原来有3+3=63+3=63+3=6个111,而顺数最后一位都为111,消去,剩下444个111,所以不为奇数。
所以只有原来的111的个数为奇数的,最后才能成为答案。
所以最后统计一下奇数个111的个数,那么答案就是奇数的和偶数的组合,令奇数个111的个数为ttt个,那么答案就为t×(n−t)t\times(n-t)t×(n−t)。
- 分析
如果直接统计的话,复杂度为O(nlogv)O(nlogv)O(nlogv)的,而logvlogvlogv可以达到303030,那么复杂度最大为三亿,显然1.5s1.5s1.5s是跑不过的,所以考虑优化:
- 我们按照位进行分治统计,复杂度降为O(nloglogv)O(nloglogv)O(nloglogv).
- 我们预处理151515位的所有数的二进制位的111的个数,那么一个数字可以看做两个151515位的数字拼接而成,所以拆开计算和即可,复杂度降为O(215+n)O(2^{15}+n)O(215+n)
- 小技巧
对于统计2152^{15}215内的数的二进制位的个数,我们不用15×21515\times 2^{15}15×215枚举统计,我们可以用类似DP+lowbitDP+lowbitDP+lowbit的方式统计(lowbit(i)=i&(−i)lowbit(i)=i\&(-i)lowbit(i)=i&(−i)为找到二进制最低位的111),转移如下:
bitcnt[i]=bitcnt[i xor lowbit(i)]+1bitcnt[i]=bitcnt[i\ \mathbf{xor}\ lowbit(i)]+1bitcnt[i]=bitcnt[i xor lowbit(i)]+1
我们发现它的实质是每次消除最低位的111,所以贡献+1+1+1即可。
那么复杂度即为O(215)O(2^{15})O(215)。
原题题目地址【IN-LuoGu】
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const int S=1<<15|1,s=(1<<15)-1;
ll n,a,b,c,d,x;
ll t1,bit[S];
void init(){
for(RG int i=1;i<S;i++){bit[i]=bit[i^lowbit(i)]+1;}
}
void calc(int a){
int a1=a&s,a2=a>>15;
int cnt1=bit[a1]+bit[a2];
if(cnt1&1)++t1;
}
int main(){
init();
scanf("%lld%lld%lld%lld%lld%lld",&n,&a,&b,&c,&d,&x);
for(RG int i=1;i<=n;i++){x=(a*x%d*x%d+b*x%d+c)%d;calc(x);}
printf("%lld\n",1ll*(n-t1)*t1);
return 0;
}