转自:http://blog.csdn.net/u014679804/article/details/48462413
题目大意:给一个字符串,求的循环最大表示,以及方向。
1、可用最大表示法求出顺时针的最大表示的最小开始位置,记为p1。利用该位置求出顺时针的最大表示字符串,记为s1
2、然后将字符串倒置,再用一次最大表示法。注意此时求出来的位置p其实是下标最大的开始位置p2,即p2=n-(p+1)+1。但可利用该位置求出逆时针的最大表示字符串,记为s2
3、将倒置的字符串扩充至2倍长度,利用KMP算法求出s2在该字符串中的最后出现位置p(即原串中的最小开始位置),即原串中的位置为n-(p+1)+1
4、比较p2和n-(p+1)+1,p2取较小值。
5、比较s1、s2得到结果。
有关证明:点击打开链接
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- int work(int len,char pat[])
- {
- int i=0,j=1,k=0;
- while(i<len && j<len && k<len)
- {
- int t = pat[(i+k)%len] - pat[(j+k)%len];
- if(!t) k++;
- else
- {
- if(t>0) j = j+k+1;
- else i = i+k+1;
- if(i == j) j++;
- k = 0 ;
- }
- }
- return i<j?i:j;
- }
-
- int Next[20005];
-
- void getNext(char *T)
- {
- int i=0,j=-1;
- Next[0]=-1;
- while(T[i]!='\0')
- {
- if(j==-1||T[i]==T[j]) Next[++i]=++j;
- else j=Next[j];
- }
- }
-
- int kmp(char *S,char *T)
- {
- int i=0,j=0,ans=-1,l1=strlen(S),l2=strlen(T);
- while(i<l1)
- {
- if(j==-1||S[i]==T[j]) ++i,++j;
- else j=Next[j];
-
- if(j>=l2){
- if(i<l1) ans=max(ans,i-l2+1);
- j=Next[j];
- }
- }
- return ans;
- }
-
- char s[40005],rs[20005],s1[20005],s2[20005];
-
- int main()
- {
- int n,T,p,p1,p2;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d%s",&n,s);
- p=work(n,s),p1=p+1;
- int cnt=0;
- while(cnt<n)
- {
- s1[cnt++]=s[p];
- p=(p+1)%n;
- }
- s1[cnt]='\0';
-
- for(int i=0;i<n;++i) rs[i]=s[n-1-i];
- rs[n]='\0';
-
- p=work(n,rs),p2=n-(p+1)+1;
- cnt=0;
- while(cnt<n)
- {
- s2[cnt++]=rs[p];
- p=(p+1)%n;
- }
- s2[cnt]='\0';
-
- for(int i=0;i<n;++i) s[i]=s[i+n]=rs[i];
- s[n+n]='\0';
-
- getNext(s2);
- p2=min(p2,n-kmp(s,s2)+1);
-
- int flag=strcmp(s1,s2);
- if(flag>0) printf("%d 0\n",p1);
- else if(flag<0) printf("%d 1\n",p2);
- else printf("%d %d\n",min(p1,p2),p1<=p2?0:1);
- }
- return 0;
- }