[NOIP2020] 字符串匹配
大致题意
给一个字符串\(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\)pts,开\(O2\)稳过
\(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;
}