http://acm.hdu.edu.cn/showproblem.php?pid=4333
t是原串 s是两个t拼在一起 exkmp求出s的每个后缀和t的公共前缀长度即可 因为要去掉所有同构串 所以还要跑kmp求出循环节长度
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int nxtt[2*maxn],nxts[2*maxn];
int l;
char t[maxn],s[2*maxn];
void kmp(char *t,int lt)
{
int i,j;
nxtt[0]=-1;
i=0,j=-1;
while(i<lt)
{
if(j==-1||t[i]==t[j])
{
i++,j++;
nxtt[i]=j;
}
else j=nxtt[j];
}
}
void exkmp(char *t,int lt)
{
int i=0,j,po;
nxtt[0]=lt;//初始化next[0]
while(t[i]==t[i+1]&&i+1<lt)//计算next[1]
i++;
nxtt[1]=i;
po=1;//初始化po的位置
for(i=2;i<lt;i++)
{
if(nxtt[i-po]+i<nxtt[po]+po)//第一种情况,可以直接得到next[i]的值
nxtt[i]=nxtt[i-po];
else//第二种情况,要继续匹配才能得到next[i]的值
{
j=nxtt[po]+po-i;
if(j<0)j=0;//如果i>po+next[po],则要从头开始匹配
while(i+j<lt&&t[j]==t[j+i])//计算next[i]
j++;
nxtt[i]=j;
po=i;//更新po的位置
}
}
}
void solve(char *s,int ls,char *t,int lt)
{
int i=0,j,po;
while(s[i]==t[i]&&i<lt&&i<ls)//计算ex[0]
i++;
nxts[0]=i;
po=0;//初始化po的位置
for(i=1;i<ls;i++)
{
if(nxtt[i-po]+i<nxts[po]+po)//第一种情况,直接可以得到ex[i]的值
nxts[i]=nxtt[i-po];
else//第二种情况,要继续匹配才能得到ex[i]的值
{
j=nxts[po]+po-i;
if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配
while(i+j<ls&&j<lt&&s[j+i]==t[j])//计算ex[i]
j++;
nxts[i]=j;
po=i;//更新po的位置
}
}
}
int main()
{
int tt,cas,i,ans1,ans2,ans3,div;
scanf("%d",&tt);
for(cas=1;cas<=tt;cas++)
{
scanf("%s",t);
l=strlen(t);
for(i=0;i<l;i++) s[i]=s[i+l]=t[i];
exkmp(t,l);
solve(s,2*l,t,l);
ans1=ans2=ans3=0;
for(i=0;i<l;i++)
{
if(nxts[i]==l) ans2++;
else
{
if(s[i+nxts[i]]<s[nxts[i]]) ans1++;
else ans3++;
}
}
kmp(t,l);
if(l!=nxtt[l]&&l%(l-nxtt[l])==0) div=l/(l-nxtt[l]);
else div=1;
printf("Case %d: %d %d %d\n",cas,ans1/div,ans2/div,ans3/div);
}
return 0;
}