您的位置:首页 > 其它

hdu 5442 Favorite Donut(后缀数组)

2015-09-16 10:44 211 查看
题目: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
='\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);
		else
			printf("%d 0\n",p1);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: