[NOIP2020] 字串匹配
阿新 • • 發佈:2021-01-08
大致題意
給一個字串\(S\),求\(S=(AB)^iC\)的方案數,其中\(F(A)≤F(C)\),\(F(S)\)表示字串 \(S\) 中出現奇數次的字元的數量
分析
設\(cnt_i\)表示奇數字符數小於等於\(i\)的\(A\)的個數
列舉\(AB\)的長度,然後用\(KMP\)的\(next\)陣列去列舉迴圈次數\(i\),將小於等於\(C\)中奇數字符的數量的\(A\)的方案,也就是\(cnt_{j}\)(\(j\)為\(C\)中出現奇數次字元從數量)加到答案中,並更新一下\(cnt\)
最壞時間複雜度\(O(n×(logn+26))\),不開\(O2\) \(92\)~\(96\)
\(code\)
/* xcxc82 */ #include<bits/stdc++.h> using namespace std; const int MAXN = (1<<20)+10; inline int read(){ int X=0; bool flag=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();} while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} if(flag) return X;return ~(X-1); } int pre[MAXN],suf[MAXN],next[MAXN],pre_value[30]; int buc[30]; bool vis[30]; int T,n; long long ans; string s; void clear(){ ans = 0; memset(vis,false,sizeof(vis)); memset(pre,0,sizeof(pre)); memset(suf,0,sizeof(suf)); memset(next,0,sizeof(next)); memset(buc,0,sizeof(buc)); memset(pre_value,0,sizeof(pre_value)); } void kmp(){ int j = 0; for(int i=2;i<=n;i++){ while(j>0&&s[i]!=s[j+1]) j = next[j]; if(s[i]==s[j+1]) j++; next[i] = j; } } signed main(){ T = read(); while(T--){ int cnt = 0; clear(); cin>>s; s = ' '+s; n = s.length()-1; for(int i=1;i<=n;i++){ if(!vis[s[i]-'a'+1]) vis[s[i]-'a'+1] = 1,cnt++; } kmp(); for(int i=1;i<=n;i++){ int now = s[i]-'a'+1; buc[now]++; if(buc[now]&1) pre[i] = pre[i-1]+1; else pre[i] = pre[i-1]-1; } memset(buc,0,sizeof(buc)); for(int i=n;i>=1;i--){ int now = s[i]-'a'+1; buc[now]++; if(buc[now]&1) suf[i] = suf[i+1]+1; else suf[i] = suf[i+1]-1; } for(int i=1;i<n;i++){ if(i>1){ for(int j=i;j<n;j+=i){ if((i%(j-next[j])==0&&j/(j-next[j])>1)||(j==i)) ans+=(long long)(pre_value[suf[j+1]]); else break; } } for(int j=pre[i];j<=cnt;j++){ pre_value[j]++; } } printf("%lld\n",ans); } return 0; }