给定一个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 }
来源:https://www.cnblogs.com/HocRiser/p/9163705.html