[PKUSC2018]神仙的游戏(FFT)

给定一个01?串,对所有len询问是否存在一种填法使存在长度为len的border。

首先有个套路的性质:对于一个长度为len的border,这个字符串一定有长度为n-len的循环节(最后可以不完整)。

逆推得到,如果有一个0位置和一个1位置之差为len,则所有len的因数k的n-k都不可能成为border。

先将b翻转,作差卷起来,然后$O(n\log n)$枚举倍数即可。

$A(x)=x^{n-1}A(\frac 1x)$是作差卷积的本质。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int N=3000010,mod=998244353,G=3;
 8 int n,len,l,a[N],b[N],rev[N],lg[N];
 9 char s[N];
10 
11 int ksm(int a,int b){
12     int res=1;
13     for (; b; a=1ll*a*a%mod,b>>=1)
14         if (b & 1) res=1ll*res*a%mod;
15     return res;
16 }
17 
18 void NTT(int a[],int n,int f){
19     for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
20     for (int i=1; i<n; i<<=1){
21         int wn=ksm(G,(f==1) ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1));
22         for (int p=i<<1,j=0; j<n; j+=p)
23             for (int w=1,k=0; k<i; k++,w=1ll*w*wn%mod){
24                 int x=a[j+k],y=1ll*w*a[i+j+k]%mod;
25                 a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
26             }
27     }
28     if (f==1) return;
29     int inv=ksm(n,mod-2);
30     for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod;
31 }
32 
33 int main(){
34     freopen("pkub.in","r",stdin);
35     freopen("pkub.out","w",stdout);
36     scanf("%s",s); n=strlen(s);
37     for (len=1; len<=(n<<1); len<<=1) l++;
38     for (int i=0; i<len; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
39     for (int i=0; i<n; i++) a[i]=s[i]=='0',b[i]=s[n-i-1]=='1';
40     NTT(a,len,1); NTT(b,len,1);
41     for (int i=0; i<len; i++) a[i]=1ll*a[i]*b[i]%mod;
42     NTT(a,len,-1);
43     long long ans=1ll*n*n;
44     for (int i=1; i<n; i++){
45         int f=1;
46         for (int j=i; j<n; j+=i) if (a[n-j-1]|a[n+j-1]) { f=0; break; }
47         if (f) ans^=1ll*(n-i)*(n-i);
48     }
49     printf("%lld\n",ans);
50     return 0;
51 }

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/9163705.html