您的位置:首页 > 其它

HDU 5442 Favorite Donut(字符串最大表示法)

2016-08-25 10:00 363 查看
Description

由n个字符构成一个环,选定一个起点和一个方向(顺时针或逆时针),使得该字符串字典序最大,如果多个答案,优先选择起点编号小的,如果同一起点两个方向都是最优解则选择顺时针方向的解

Input

第一行一整数T表示用例组数,对于每组用例首先输入一整数n表示字符个数,之后一个长度为n的字符串

Output

对于每组用例,输出最优解的起点编号和方向(顺时针0,逆时针1)

Sample Input

2

4

abab

4

aaab

Sample Output

2 0

4 0

Solution

设该串为s,其反串为ss,问题转化为求s的最大表示(最小下标开始)和ss的最大表示(最大下标开始),第一个问题就是常规的字符串最大表示法,第二个问题是在第一个问题上稍作修改(具体实现见代码),得到两个最优解后比较一下选出字典序较大的那个即可,注意反串求出的下标要转化成在原串中的下标(pos->n-pos-1)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 22222
int min_express_min_pos(char *x,int n)
{
int i=0,j=1,k=0;
while(i<n&&j<n)
{
k=0;
while(x[i+k]==x[j+k]&&k<n)k++;
if(k==n)return min(i,j);
if(x[i+k]<x[j+k])i=max(i+k+1,j+1);
else j=max(j+k+1,i+1);
}
return min(i,j);
}
int min_express_max_pos(char *x,int n)
{
int i=0,j=1,k=0;
while(i<n&&j<n)
{
k=0;
while(x[i+k]==x[j+k]&&k<n)k++;
if(k==n)return n-abs(i-j)+i;
if(x[i+k]<x[j+k])i=max(i+k+1,j+1);
else j=max(j+k+1,i+1);
}
return max(i%n,j%n);
}
int T,n;
char s[2*maxn],ss[2*maxn],a[maxn],b[maxn];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%s",&n,s);
for(int i=0;i<n;i++)ss[i]=s[n-1-i];
for(int i=0;i<n;i++)s[i+n]=s[i],ss[i+n]=ss[i];
int pos1=min_express_min_pos(s,n);
int pos2=min_express_max_pos(ss,n);
for(int i=0;i<n;i++)a[i]=s[i+pos1],b[i]=ss[i+pos2];
a
=b
='\0';
if(strcmp(a,b)>0)printf("%d 0\n",pos1+1);
else if(strcmp(a,b)<0)printf("%d 1\n",n-pos2);
else
{
if(n-pos2<pos1+1)printf("%d 1\n",n-pos2);
else printf("%d 0\n",pos1+1);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: