先将字符串扩增两倍,与原来的进行匹配,每一个匹配过程中,比较两个串ex【i】和i+ex【i】位的大小就可以判断大小,再利用标准的kmp算法取得nxt数组,判定原串是否为循环。如果是循环串,则要对答案除以循环次数。
#include<bits/stdc++.h>
using namespace std;
#define maxn 100010
typedef long long LL;
int ans[3];
int Next[maxn<<1];
int ex[maxn<<1];
char str[maxn<<1];
int nxt[maxn<<1];
char s[maxn<<1];
int t;
void getNext(char str[])
{
int i = 0,j,po,len = strlen(str);
Next[0] = len;
while(str[i]==str[i+1]&&i+1<len)
i++;
Next[1] = i;po = 1;
for(i = 2; i < len;i++)
{
if(Next[i-po]+i<Next[po]+po)
Next[i]=Next[i-po];
else
{
j=Next[po]+po-i;
if(j<0) j=0;
while(i+j<len&&str[j]==str[j+i])
j++;
Next[i]=j;
po=i;
}
}
}
void ex_kmp(char str1[], char str2[])
{
int i =0,j,po,len1=strlen(str1);
int len2= strlen(str2);
getNext(str2);
while(str1[i] == str2[i]
&&i < len2&&i < len1) i++;
ex[0] = i;
po = 0;
for(i = 1;i<len1;i++)
{
if(Next[i-po]+i<ex[po]+po)
ex[i] = Next[i-po];
else
{
j = ex[po] - i + po;
if(j < 0) j = 0;
while(i + j < len1&&j < len2
&&str1[i + j] == str2[j]) j++;
ex[i] = j;
po = i;
}
}
}
void getnext(char str[])
{
int len = strlen(str);
nxt[0] = -1;
int i = 0,j = -1;
while(i < len)
{
if(str[i]==str[j]||j==-1)
nxt[++i] = ++j;
else
j = nxt[j];
}
}
int main()
{
scanf("%d",&t);
int laz = 0;
while(t--)
{
scanf("%s", str);
int len = strlen(str);
for(int i = 0; i < len;i++)
{
s[i] = str[i];
str[i+len] = str[i];
}
ex_kmp(str, s);
getnext(s);
memset(ans, 0, sizeof ans);
for(int i = 0;i < len; i++)
{
if(ex[i] >= len) ans[1]++;
else if(ex[i] < len)
{
if(str[ex[i]+i]<s[ex[i]]) ans[0]++;
else ans[2]++;
}
}
int mod = 1;
if(len%(len-nxt[len])==0) mod = len/(len-nxt[len]);
printf("Case %d: %d %d %d\n", ++laz, ans[0]/mod, ans[1]/mod, ans[2]/mod);
}
}