题意:
给出一个数字的串,每次可以选择一个位置,然后把位置后面的放到这个串的最前面构成新的串。问构成的新的串中等于这个串,小于这个串,大于这个串的个数。
题解:
两种做法。
一种是直接应用扩展kmp,将原串复制一遍得到两倍的串,然后原串去匹配这个串。得到每个位置的最长前缀长度,如果长度extend[i]>=len说明相等,否则比较下个字符的大小。
第二种做法是从定义出发,扩展kmp的next数组存的就是串从i位置开始和本身的最大前缀,那么只要用next[i]就能进行比较。
第二种做法比较高效!
方法一:
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; //typedef long long lld; const int oo=0x3f3f3f3f; //const lld OO=1LL<<61; const int MOD=10007; const int maxn=2000010; char str[maxn],s[maxn]; int next[maxn],extend[maxn]; void get_next(char T[],int len) { int i=0;next[i]=-1; int j=-1; while(i<len) { if(j==-1||T[i]==T[j]) { i++;j++; next[i]=j; } else j=next[j]; } } void get_extend(char T[],int len) { int k=0; next[0]=len; while(k<len-1&&T[k]==T[k+1])k++; next[1]=k; k=1; for(int i=2;i<len;i++) { int p=k+next[k]-1,L=next[i-k];///p表示目前匹配的最大长度 if(i+L-1>=p)///大于,要更新 { int j=max(p-i+1,0); while(i+j<len&&T[i+j]==T[j])j++; next[i]=j; k=i; } else next[i]=L; } } void kmp_extend(char S[],char T[],int lenS,int lenT) { int k=0; while(k<lenT&&k<lenS&&S[k]==T[k])k++; extend[0]=k; k=0; for(int i=1;i<lenS;i++) { int p=k+extend[k]-1,L=next[i-k]; if(i+L-1>=p) { int j=max(p-i+1,0); while(i+j<lenS&&j<lenT&&S[i+j]==T[j])j++; extend[i]=j; k=i; } else extend[i]=L; } } int main() { int T,L,E,G; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { scanf("%s",s); int len=strlen(s); strcpy(str,s); strcat(str,s); get_next(s,len); int cir=(len%(len-next[len]))==0?len/(len-next[len]):1; get_extend(s,len); kmp_extend(str,s,len*2,len); L=E=G=0; for(int i=0;i<len;i++) { if(extend[i]>=len) E++; else if(str[i+extend[i]]>s[extend[i]])G++; else L++; } printf("Case %d: %d %d %d\n",cas,L/cir,E/cir,G/cir); } return 0; } /** addfg addfg addad addad 34134 */
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; //typedef long long lld; const int oo=0x3f3f3f3f; //const lld OO=1LL<<61; const int MOD=10007; const int maxn=2000010; char str[maxn],s[maxn]; int next[maxn],extend[maxn]; void get_next(char T[],int len) { int i=0;next[i]=-1; int j=-1; while(i<len) { if(j==-1||T[i]==T[j]) { i++;j++; next[i]=j; } else j=next[j]; } } void get_extend(char T[],int len) { int k=0; next[0]=len; while(k<len-1&&T[k]==T[k+1])k++; next[1]=k; k=1; for(int i=2;i<len;i++) { int p=k+next[k]-1,L=next[i-k];///p表示目前匹配的最大长度 if(i+L-1>=p)///大于,要更新 { int j=max(p-i+1,0); while(i+j<len&&T[i+j]==T[j])j++; next[i]=j; k=i; } else next[i]=L; } } int main() { int T,L,E,G; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { scanf("%s",s); int len=strlen(s); strcpy(str,s); strcat(str,s); get_next(s,len); int cir=(len%(len-next[len]))==0?len/(len-next[len]):1; get_extend(str,2*len); L=E=G=0; for(int i=0;i<len;i++) { if(next[i]>=len)E++; else if(str[i+next[i]]>str[next[i]])G++; else L++; } printf("Case %d: %d %d %d\n",cas,L/cir,E/cir,G/cir); } return 0; } /** addfg addfg addad addad 34134 */