标签:
Description
Input
Output
Sample Input
Sample Output
题意:给一个数,从这个数的尾端取一个数字放在前段,循环进行,输出有多少得到的数大于原来的数、等于原来的数、小于原来的数,注意相同的数只计算一次。‘
思路:使用ex_KMP算法可以得到从第i个字符开始和前缀匹配的最大长度,所以和原来的数进行比较大小时,可以减少比较次数节省时间。由于相同的数只能计算一次,所以可以使用KMP算法找出最小周期,对最小周期的字符进行计算。
代码如下:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int nex[100005],nex2[100005]; int a,b,c; char str[100005]; void ex_next(int length) { ///nex[i]: 以第i位置开始的子串与T的前缀的最大长度; int i; nex[0]=length; for(i=0; i<length-1&&str[i]==str[i+1]; i++); ///前缀都是同一个字母的时候; nex[1]=i; int a=1;///a为使匹配到最远的地方时的起始匹配地点; for(int k=2; k<length; k++) { int p=a+nex[a]-1,L=nex[k-a]; if( (k-1)+L>=p ) { int j=(p-k+1)>0?(p-k+1):0; while(k+j<length&&str[k+j]==str[j]) j++; /// 枚举(p+1,length) 与(p-k+1,length) 区间比较; nex[k]=j,a=k; } else nex[k]=L; } } void next_(int len) { int k=0; nex2[0]=0; for(int i=1; i<len; i++) { while(k>0&&str[k]!=str[i]) k=nex2[k-1]; if(str[k]==str[i]) k++; nex2[i]=k; } } void solve(int len) { int t,s; for(int i=1; i<len; i++) { t=nex[i]; if(i+t<len) { if(str[t+i]>str[t]) c++; else a++; } else { s=nex[t]; if(s<i) { if(str[t+s]<str[s]) c++; else a++; } } } } int main() { int T,Case=1; scanf("%d",&T); while(T--) { a=0; b=1; c=0; scanf("%s",str); int len=strlen(str); next_(len); int minn=len-nex2[len-1]; if(len%minn==0) str[minn]=‘\0‘; else minn=len; //cout<<minn<<endl; ex_next(minn); solve(minn); printf("Case %d: %d %d %d\n",Case++,a,b,c); } return 0; }
KMA & ex_KMP---Revolving Digits
标签:
原文地址:http://www.cnblogs.com/chen9510/p/5350164.html