loj函數
給你一個只有01
和?
的字符串,問你是否存在一種把?
改爲01
的方案使串存在一個長度爲\(1-n\)的\(border\)。\(n\le5\times10^5\)spa
這種題都不會我仍是太菜了。
有一檔部分分是「01
的個數不超過\(5000\)」。這個其實對正解的提示是蠻大的。
有一個顯然的結論:存在一個長度爲\(len\)的\(border\)當且僅當對於\(\forall i\in[1,len]\) 有 \(s[i]=s[n-len+i]\)。(感謝熱心網友找出這裏的一個錯誤)
或者這樣說,把全部位置在模\(n-len\)意義下分組,同一組裏的01
要所有相同。
那麼,若是存在一組0
和1
他們的下標之差爲\(x\),那麼全部\(y|x\)的\(n-y\)都不可能成爲\(border\)。
這樣\(67\)分就能夠寫一個\(5000^2\)枚舉01
對統計,而後每次掃一遍倍數\(O(n\log n)\)計算答案。code
考慮正解。如今的複雜度瓶頸在於枚舉01
對。
搞兩個生成函數\(A(x)\)和\(B(x)\),\(A(x)=\sum_{i=0}^{n-1}[s_i==0]x^i\),\(B(x)=\sum_{i=0}^{n-1}[s_i==1]x^i\)。
咱們知道,多項式卷積計算的是全部下標之和爲必定值的乘積之和,也就是\(C_i=\sum_{j+k=i}A_jB_k\)。如今咱們要統計的是差爲定值的。
把一個多項式\(reverse\)過來不就行了麼。形式化地,令\(A(x)=x^{n-1}A(\frac 1x)\),而後計算\(C(x)=A(x)B(x)\)獲得的第\(i\)次項係數就是知足「1
的下標減0
的下標等於\(i-n\)」的01
對數。
複雜度\(O(n\log n)\)。ip
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 3e6+5; const int mod = 998244353; int n,len,a[N],b[N],rev[N],l,og[N]; char s[N]; int fastpow(int a,int b){ int res=1; while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;} return res; } void ntt(int *P,int opt){ for (int i=0;i<len;++i) if (i<rev[i]) swap(P[i],P[rev[i]]); for (int i=1;i<len;i<<=1){ int W=fastpow(3,(mod-1)/(i<<1)); if (opt==-1) W=fastpow(W,mod-2); og[0]=1; for (int j=1;j<i;++j) og[j]=1ll*og[j-1]*W%mod; for (int p=i<<1,j=0;j<len;j+=p) for (int k=0;k<i;++k){ int x=P[j+k],y=1ll*og[k]*P[j+k+i]%mod; P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod; } } if (opt==-1) for (int i=0,Inv=fastpow(len,mod-2);i<len;++i) P[i]=1ll*P[i]*Inv%mod; } int main(){ scanf("%s",s);n=strlen(s); for (len=1;len<=(n<<1);len<<=1) ++l;--l; for (int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l); for (int i=0;i<n;++i) a[i]=s[i]=='0',b[i]=s[n-i-1]=='1'; ntt(a,1);ntt(b,1); for (int i=0;i<len;++i) a[i]=1ll*a[i]*b[i]%mod; ntt(a,-1); long long ans=1ll*n*n; for (int i=1;i<n;++i){ int fg=1; for (int j=i;j<n;j+=i) if (a[n-j-1]|a[n+j-1]) {fg=0;break;} if (fg) ans^=1ll*(n-i)*(n-i); } printf("%lld\n",ans);return 0; }