hdu5442 最小最大表示法+kmp

转自: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得到结果。


有关证明:点击打开链接


[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<cstring>  
  4. using namespace std;  
  5. int work(int len,char pat[])  //最大表示法  
  6. {  
  7.    int i=0,j=1,k=0;  
  8.    while(i<len && j<len && k<len)  
  9.    {  
  10.        int t = pat[(i+k)%len] - pat[(j+k)%len];  
  11.        if(!t) k++;  
  12.        else  
  13.        {  
  14.            if(t>0) j = j+k+1;  
  15.            else i = i+k+1;  
  16.            if(i == j) j++;  
  17.            k = 0 ;  
  18.        }  
  19.    }  
  20.    return i<j?i:j;  
  21. }  
  22.   
  23. int Next[20005];  
  24.   
  25. void getNext(char *T)  
  26. {  
  27.     int i=0,j=-1;  
  28.     Next[0]=-1;  
  29.     while(T[i]!='\0')  
  30.     {  
  31.         if(j==-1||T[i]==T[j]) Next[++i]=++j;  
  32.         else j=Next[j];  
  33.     }  
  34. }  
  35.   
  36. int kmp(char *S,char *T)  
  37. {  
  38.     int i=0,j=0,ans=-1,l1=strlen(S),l2=strlen(T);  
  39.     while(i<l1)  
  40.     {  
  41.         if(j==-1||S[i]==T[j]) ++i,++j;  
  42.         else j=Next[j];  
  43.   
  44.         if(j>=l2){  
  45.             if(i<l1) ans=max(ans,i-l2+1);  
  46.             j=Next[j];  
  47.         }  
  48.     }  
  49.     return ans;  
  50. }  
  51.   
  52. char s[40005],rs[20005],s1[20005],s2[20005];  
  53.   
  54. int main()  
  55. {  
  56.     int n,T,p,p1,p2;  
  57.     scanf("%d",&T);  
  58.     while(T--)  
  59.     {  
  60.         scanf("%d%s",&n,s);  
  61.         p=work(n,s),p1=p+1;  
  62.         int cnt=0;  
  63.         while(cnt<n)  
  64.         {  
  65.             s1[cnt++]=s[p];  
  66.             p=(p+1)%n;  
  67.         }  
  68.         s1[cnt]='\0';  
  69.   
  70.         for(int i=0;i<n;++i) rs[i]=s[n-1-i];  
  71.         rs[n]='\0';  
  72.   
  73.         p=work(n,rs),p2=n-(p+1)+1;  
  74.         cnt=0;  
  75.         while(cnt<n)  
  76.         {  
  77.             s2[cnt++]=rs[p];  
  78.             p=(p+1)%n;  
  79.         }  
  80.         s2[cnt]='\0';  
  81.   
  82.         for(int i=0;i<n;++i) s[i]=s[i+n]=rs[i];  
  83.         s[n+n]='\0';  
  84.   
  85.         getNext(s2);  
  86.         p2=min(p2,n-kmp(s,s2)+1);  
  87.   
  88.         int flag=strcmp(s1,s2);  
  89.         if(flag>0) printf("%d 0\n",p1);  
  90.         else if(flag<0) printf("%d 1\n",p2);  
  91.         else printf("%d %d\n",min(p1,p2),p1<=p2?0:1);  
  92.     }  
  93.     return 0;  
  94. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值