http://acm.hdu.edu.cn/showproblem.php?pid=4333
t是原串 s是两个t拼在一起 exkmp求出s的每个后缀和t的公共前缀长度即可 因为要去掉所有同构串 所以还要跑kmp求出循环节长度
using namespace std;
const int maxn=1e5+10;
int nxtt[2*maxn];
char ch[2*maxn];
int n;
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,j,p;
nxtt[0]=lt;
i=0;
while(i+1<lt&&t[i]==t[i+1]) i++;
nxtt[1]=i;
p=1;
for(i=2;i<lt;i++){
if(i+nxtt[i-p]<p+nxtt[p]) nxtt[i]=nxtt[i-p];
else{
j=max(0,p+nxtt[p]-i);
while(i+j<lt&&t[j]==t[i+j]) j++;
nxtt[i]=j;
p=i;
}
}
}
int main()
{
int t,cas,i,ans1,ans2,len;
scanf("%d",&t);
for(cas=1;cas<=t;cas++){
scanf("%s",ch);
n=strlen(ch);
kmp(ch,n);
len=n-nxtt[n];
if(n%len!=0) len=1;
else len=n/len;
for(i=n;i<2*n;i++) ch[i]=ch[i-n];
n*=2;
exkmp(ch,n);
ans1=0,ans2=0;
for(i=0;i<n/2;i++){
if(nxtt[i]<n/2){
if(ch[i+nxtt[i]]<ch[nxtt[i]]) ans1++;
else ans2++;
}
}
printf("Case %d: %d %d %d\n",cas,ans1/len,1,ans2/len);
}
return 0;
}