hdu 5442 Favorite Donut(后缀数组)

来源:互联网 发布:js获取跳转前的url 编辑:程序博客网 时间:2024/05/22 04:17

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5442

题意:给定长度为n的字符串s(s是环),然后以某一点顺时针或者逆时针出发遍历字符串s将得到一个t,求一个字典序最大的字符串t的起始位置。字典序相同的选起始位置靠前的,位置相同的选顺时针的。

分析:将原来的字符串添加字符,使得前n个字符,每个字符与其后面的n-1个字符正是循环遍历的字符串。比如aabca--->aabcaaabc (顺时针) aabca---->acbaaacba (逆时针),然后对新构造出来的字符串求其后缀数组,那么可以得到字典序最大的两个字符串(两个方向),把字符串取出来,然后比较一下就行了。

ps:对于顺时针的字符串末尾要加一个表示负无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠前的优先选择。

对于逆时针的字符串末尾要加一个表示正无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠后的优先选择。这里的靠后是反转之后的字符串,再反过来就是靠前的了。

代码:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <set>using namespace std;const int maxn = 1e5+6;char in[maxn],s[maxn];int sa[maxn],t[maxn],t2[maxn],c[maxn],n;void build_sa(int n,int m){int i,*x=t,*y=t2;for(i=0;i<m;i++)c[i]=0;for(i=0;i<n;i++)c[x[i]=s[i]]++;for(i=1;i<m;i++)c[i]+=c[i-1];for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;for(int k=1;k<=n;k<<=1){int p=0;for(i=n-k;i<n;i++)y[p++]=i;for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;for(i=0;i<m;i++)c[i]=0;for(i=0;i<n;i++)c[x[y[i]]]++;for(i=1;i<m;i++)c[i]+=c[i-1];for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1;x[sa[0]]=0;for(i=1;i<n;i++)x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;if(p>=n)break;m=p;}}void GetSuffix(char buf[],char str[],int p,int n){for(int cnt=0,i=p;cnt<n;cnt++,i++)buf[cnt]=str[i];buf[n]='\0';}char ts[maxn],s1[maxn],s2[maxn];int main(){int ncase,n,i,j,p1,p2,len1,len2;scanf("%d",&ncase);while(ncase--){scanf("%d%s",&n,in);strcpy(ts,in);for(i=0;i<n-1;i++)ts[n+i]=ts[i];ts[n+i]='\0';len1=strlen(ts);strcpy(s,ts);build_sa(len1+1,255);for(i=len1;i>=0 && sa[i]>=n;i--);p1=sa[i];GetSuffix(s1,ts,p1,n);strcpy(ts,in);reverse(ts,ts+n);for(i=0;i<n-1;i++)ts[n+i]=ts[i];ts[n+i]='\0';len2=strlen(ts);ts[len2]='z'+1;strcpy(s,ts);build_sa(len2+1,255);for(i=len2;i>=0 && sa[i]>=n;i--) ;p2=sa[i];GetSuffix(s2,ts,p2,n);//printf("%s\n%s\n",s1,s2);p1=p1+1;p2=n-p2;int temp=strcmp(s1,s2);if(temp!=0)temp==1?printf("%d 0\n",p1):printf("%d 1\n",p2);else if(p1!=p2)p1<p2?printf("%d 0\n",p1):printf("%d 1\n",p2);elseprintf("%d 0\n",p1);}return 0;}

0 0