【XR-3】Unknown Mother-Goose(暴力,位运算,分块)
解:
暴力:开一个有1e9bit的ull数组,对于集合中每一个数x,令第x,2x,3x...位为1,只要找连续3位为1就好,所以答案就为连续3个1的个数,可以用__builtin_popcountll(t&(t>>1)&(t>>2))来求;
分块:为减小复杂度,可以把64位分为一块(也就是1个ull),当遇到集合中一个数x时:
x>=64时:枚举所有x的倍数;
x<64时:先算出前x个块,后面的块由前x个块循环组成。
求解:答案由块内和块间组成,把两部分加起来就可以了。
时间复杂度:O(|S|*n/64)
理论上复杂度高,但是寻址连续并且不会频繁调用系统栈,可以过。
注意:3<=x<=n;所以a[0]第一位不能区,a[m]超过n的位不能取。
代码:
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e9+9;
int n,cnt;
ull a[(N>>6)+10],b[78];
int main(){
cin>>n>>cnt;
int m=(n>>6);
while(cnt--){
int x;
cin>>x;
if(x>64){
for(int i=x;i<=n;i+=x)a[i>>6]|=(1ll<<(i&63));
}else{
for(int i=0;i<x;i++)b[i]=0;
for(int i=0;i<64*x;i+=x)b[i>>6]|=(1ll<<(i&63));
for(int i=0,j=0;i<=m;i++,j=(j==x-1)?0:j+1)a[i]|=b[j];
}
}
a[m]&=((1ll<<((n+1)&63))-1);//x<=n
if(a[0]&1)a[0]^=1;//题目要求x>=3
int ans=0;
for(int i=0;i<=m;i++)ans+=__builtin_popcountll(a[i]&(a[i]>>1)&(a[i]>>2));
for(int i=1;i<=m;i++){
ull t=(a[i-1]>>62)|((a[i]&3)<<2);
ans+=__builtin_popcountll(t&(t>>1)&(t>>2));
}
cout<<ans<<endl;
return 0;
}