Rusty String
题意:
给定一个含有两种字符'V','K'以及?的字符串,问该串可能的循环节。
解法:
首先如果对于$d$,我们有不存在 $(j-i) | d$ 且 $S_i = 'V', S_j = 'K'$ 的,那么 $d$ 为1循环节。
这样考虑对于每一个 $d$ 求出 $j-i = d$ 的 $S_i = 'V', S_j = 'K'$ 是否存在,然后 $O(nlogn)$ 筛一遍即可。
求 $j - i = d$ 的有
$$c_{n - i} = \sum_{0 \leq j \leq i} { a(j) b(n-i+j-1) }$$
$$c_{n - i} = (reva \otimes b)_{2n-i-1} = \sum_{0 \leq t \leq 2n-i-1}{ reva_t b_{2n-i-1-t} }$$
标准卷积,DFT即可。
#include <bits/stdc++.h> #define PI acos(-1) const int N = 500010; using namespace std; struct EX { double real,i; EX operator+(const EX tmp)const{return (EX){real+tmp.real, i+tmp.i};}; EX operator-(const EX tmp)const{return (EX){real-tmp.real, i-tmp.i};}; EX operator*(const EX tmp)const{return (EX){real*tmp.real - i*tmp.i, real*tmp.i + i*tmp.real};}; }; int R[N<<2]; void DFT(EX a[],int n,int tp_k) { for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]); for(int d=1;d<n;d<<=1) { EX wn = (EX){cos(PI/d), sin(PI/d)*tp_k}; for(int i=0;i<n;i += (d<<1)) { EX wt = (EX){1,0}; for(int k=0;k<d;k++, wt = wt*wn) { EX A0 = a[i+k], A1 = wt * a[i+k+d]; a[i+k] = A0+A1; a[i+k+d] = A0-A1; } } } if(tp_k==-1) for(int i=0;i<n;i++) a[i] = (EX){a[i].real/n, a[i].i/n}; } EX A[N<<2],B[N<<2],C[N<<2]; char S[N]; int n; bool del[N],ans[N]; void calc(char ch1,char ch2,int tot) { for(int i=0;i<tot;i++) A[i] = B[i] = (EX){0,0}; for(int i=0;i<n;i++) if(S[i]==ch1) B[i] = (EX){1,0}; for(int i=1;i<=n;i++) if(S[n-i]==ch2) A[i] = (EX){1,0}; DFT(A,tot,1); DFT(B,tot,1); for(int i=0;i<tot;i++) C[i] = A[i]*B[i]; DFT(C,tot,-1); for(int i=0;i<n;i++) { int tmp = (int)(C[2*n-i-1].real+0.5); if(tmp) del[i] = 1; } } int main() { int T; cin>>T; while(T--) { scanf("%d%s",&n,S); int L = 0,tot; while((1<<L)<n+n) L++; tot = (1<<L); for(int i=1;i<tot;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); for(int i=0;i<n;i++) del[i] = 0, ans[i+1] = 0; calc('V','K',tot); calc('K','V',tot); for(int i=n-1;i>=0;i--) if(!del[i]) ans[n-i-1] = 1; ans[n] = 1; int cnt = 0; for(int i=1;i<=n;i++) { for(int j=i+i;j<=n;j+=i) ans[i] &= ans[j]; if(ans[i]) cnt++; } printf("%d\n",cnt); for(int i=1;i<=n;i++) if(ans[i]) printf("%d ",i); printf("\n"); } return 0; }