题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374
题意:给出字符串,求最小表示法和最大表示法,并输出有几次出现,其实就是最小循环节的个数
题解:最小表示法求解,KMP求解最小循环节 最小循环节 = len - Next[len] 个数必须整出,如不整除,则为1.
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 2000000+50; //开两倍的原因是要复制串长 char s1[maxn],s2[maxn]; int Next[maxn>>1]; int smallest(char *s) { int i = 0,j = 1,k = 0; int len = strlen(s); strcpy(s2,s); strcat(s,s2); while(i<len&&j<len) { k=0; while(k<len&&(s[i+k]==s[j+k])) k++; if(k>=len) break; if(s[i+k]>s[j+k]) i=max(i+k+1,j+1); else j=max(i+1,j+k+1); } return min(i,j); } int biggest(char *s) { int i = 0,j = 1,k = 0; int len = strlen(s); strcpy(s2,s); strcat(s,s2); while(i<len&&j<len) { k=0; while(k<len&&(s[i+k]==s[j+k])) k++; if(k>=len) break; if(s[i+k]<s[j+k]) i=max(i+k+1,j+1); else j=max(i+1,j+k+1); } return min(i,j); } void getNext(int len) { int i=0,j=-1; Next[0]=-1; while(i<len) { if(j==-1||s1[i]==s1[j]) i++,j++,Next[i]=j; else j=Next[j]; } } int main() { while(~scanf("%s",s1)) { int len = strlen(s1); int k1 = smallest(s1); int k2 = biggest(s1); getNext(len); int sum = len - Next[len]; if(len%sum==0) sum = len/sum; else sum=1; printf("%d %d %d %d\n",k1+1,sum,k2+1,sum); } }
时间: 2024-11-08 22:47:56