题意
给你一个数字A每次将A的末尾的数往最前面调,多次操作之后回来原来的数问你在这一个过程中比原来的A大,小,等的数各有多少
思路
将A复制一遍插入A的末尾变成AA,只需要在AA中遍历A长度的字符串对于每次的i我们判断i+len(A)长度的数字与A做比较就可以,朴素的比较是n2,我们只需要求出AA与AA的扩展kmp,extend就是与AA的最长公共前缀,如果extend[i]>=len(A)说明两者相等,如果小于只需要比较AA[i+extend[i]]与AA[extend[i]]的大小就可以。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXNUM 1000050
char s1[2*MAXNUM], s2[2*MAXNUM];//s2为待匹配字符串
int s1size, s2size;
//num[i]保存s2长度为i的前缀子串在s1中出现的数目,非必需
int num[2*MAXNUM];
//extend为s1串中对应位置开始匹配的最大前缀长度
//snext为s2串中[i,len]与s2的最长公共前缀长度
int snext[2*MAXNUM],extend[2*MAXNUM];
void getextnext()
{
int i, length = s2size;
snext[0] = length;
for (i = 0; i<length - 1 && s2[i] == s2[i + 1]; i++);
snext[1] = i;
int a = 1;
for (int k = 2; k < length; k++)
{
int p = a + snext[a] - 1, L = snext[k - a];
if ((k - 1) + L >= p)
{
int j = (p - k + 1)>0 ? (p - k + 1) : 0;
while (k + j<length && s2[k + j] == s2[j]) j++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较
snext[k] = j, a = k;
}
else snext[k] = L;
}
}
void kmpextend()
{
s1size = strlen(s1), s2size = strlen(s2);
getextnext();
int a = 0;
int MinLen = s1size>s2size ? s2size : s1size;
while (a<MinLen && s1[a] == s2[a]) a++;
extend[0] = a, a = 0;
for (int i = 1; i < s1size; i++)
{
int p = a + extend[a] - 1, L = snext[i - a];
if ((i - 1) + L >= p)
{
int j = (p -i + 1)>0 ? (p - i + 1) : 0;
while (i + j<s1size && j<s2size && s1[i + j] == s2[j])
j++;
extend[i] = j;
a = i;
}
else extend[i] = L;
}
//计算Num,可去
for (int i = 0; i < s1size; i++)
num[extend[i]]++;
for (int i = s2size - 1; i >= 1; i--)
num[i] += num[i + 1];
}
int XHJ(char str[])
{
// 已经求出next数组
int kk; // kk保存最短循环节
int len=strlen(str);
for(int i=1; i<=len; ++i)
{
if(i+snext[i]>=len){
kk = len%i ? len : i;
break;
}
}
return kk;
}
char str3[2*MAXNUM];
int main()
{
int T;cin>>T;
int kace=1;
while(T--)
{
scanf("%s",str3);
int len3=strlen(str3);
for(int i=0;i<len3;i++) s1[i]=str3[i];
for(int i=0;i<len3;i++) s1[len3+i]=str3[i];
int len1=2*len3;
s1[len1]='\0';
for(int i=0;i<len1;i++) s2[i]=s1[i];
s2[len1]='\0';
kmpextend();
int a=0,b=0,c=0;
int kk=XHJ(s1);
for(int i=0;i<kk;i++)
{
if(extend[i]>=kk) b++;
else
{
if(s1[i+extend[i]]>s1[extend[i]]) c++;
else if(s1[i+extend[i]]<s1[extend[i]]) a++;
}
}
printf("Case %d: %d %d %d\n",kace++,a,b,c);
}
return 0;
}