题意

给出一个长度为n的环状由小写字母组成的序列,请找出从何处断开,顺时针还是逆时针,使得字典序最大。如果两个字符串的字典序一样大,那么它会选择下下标最小的那个。如果某个点顺时针逆时针产生的字典序大小相同,那么优先选择顺时针的。

这个题用最大表示法+KMP很容易解决。因为最大表示法找到的是下表最小的那个字典序最大的字符串,所以正向的时候最大表示法找出来的就直接是答案,关键是逆时针的时候。我们将字符串翻转以后用最大表示法找到那个字符串s2,然后用KMP算法在翻转*2后的串中找出最后面的那个s2,这就是逆时针时候的答案。然后比较顺时针和逆时针时候的答案,选取最优的就可以了。

下面是代码。

 

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
const int maxn=+;
char s[maxn],str[maxn];
char s1[maxn],s2[maxn];
int T,n,ans1,ans2;
int get_max(char *S){
int len=strlen(S);
int i=,j=,k=;
while(i<len&&j<len&&k<len){
int t=S[(i+k)%len]-S[(j+k)%len];
if(t==)k++;
else{
if(t>)
j+=k+;
else
i+=k+;
if(i==j)j++;
k=;
}
}
return min(i,j);
}
int f[maxn];
void get_fail(char *P){
int n=strlen(P);
f[]=,f[]=;
for(int i=;i<n;i++){
int j=f[i];
while(j&&P[i]!=P[j])j=f[j];
f[i+]=P[i]==P[j]?j+:;
}
}
int find(char *T,char *P){
int res=,len=strlen(T),m=strlen(P);
get_fail(P);
int j=;
for(int i=;i<*n;i++){
while(T[i]!=P[j]&&j)j=f[j];
if(T[i]==P[j])j++;
if(j==m){
if(i-m+<n){
res=i-m+;
}
}
}
return res;
}
int main(){
scanf("%d",&T);
for(int t=;t<=T;t++){
scanf("%d",&n);
scanf("%s",str);
ans1=get_max(str);
for(int i=;i<n;i++){
s1[i]=str[(ans1+i)%n];
}
s1[n]=;
reverse(str,str+n);
int j=get_max(str);
for(int i=;i<n;i++){
s2[i]=str[(j+i)%n];
}
s2[n]=;
for(int i=;i<n;i++)
str[i+n]=str[i];
str[*n]=;
int ans2=find(str,s2);
int ok=;
ans2=n-ans2-;
// printf("%d %d\n",ans1,ans2);
// printf("%s\n%s\n",s1,s2); for(int i=;i<n;i++){
if(s1[i]>s2[i]){
ok=;
break;
}
if(s1[i]<s2[i]){
ok=-;
break;
}
}
ans1++,ans2++;
if(ok>){
printf("%d %d\n",ans1,);
}
else if(ok<){
printf("%d %d\n",ans2,);
}
else{
if(ans2<ans1){
printf("%d %d\n",ans2,);
}else if(ans1<ans2){
printf("%d %d\n",ans1,);
}else{
printf("%d %d\n",ans1,);
}
}
}
return ;
}

这个题显然也可以用后缀数组来搞。跟上面的思路差不多,顺时针的时候可以直接用sa数组找出答案(因为前面的一定长于后面的),关键是逆时针的时候如何找出下标最大的最大字典序的字符串。我们可以利用一下height数组。当height[i]==len的时候,就是我们要的答案。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
const int maxn=+;
int T,n;
char s[maxn];
char s1[maxn],s2[maxn];
int sa[maxn],c[maxn],x[maxn],y[maxn],height[maxn],rak[maxn];
void build_sa(int m){
memset(y,-,sizeof(y));
for(int i=;i<m;i++)c[i]=;
for(int i=;i<n;i++)c[x[i]=s[i]]++;
for(int i=;i<m;i++)c[i]+=c[i-];
for(int i=n-;i>=;i--)sa[--c[x[i]]]=i; for(int k=;k<=n;k<<=){
int p=;
for(int i=n-k;i<n;i++)y[p++]=i;
for(int i=;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=;i<m;i++)c[i]=;
for(int i=;i<n;i++)c[x[y[i]]]++;
for(int i=;i<m;i++)c[i]+=c[i-];
for(int i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=,x[sa[]]=;
for(int i=;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-]]&&y[sa[i]+k]==y[sa[i-]+k]?p-:p++;
if(p>=n)break;
m=p;
}
} void getHeight(){
int k=;
for(int i=;i<n;i++)rak[sa[i]]=i;
for(int i=;i<n;i++){
if(k)k--;
int j=sa[rak[i]-];
while(s[i+k]==s[j+k])k++;
height[rak[i]]=k;
}
}
int R[maxn],num;
char str[maxn];
int ans1,ans2,len;
int main(){
scanf("%d",&T);
for(int t=;t<=T;t++){
scanf("%d",&len);
scanf("%s",str);
for(int i=;i<len;i++){
s[i]=str[i];
s[i+len]=str[i];
}
n=*len;
s[n]=;
build_sa();
for(int i=n-;i>=;i--){
if(sa[i]<len){
ans1=sa[i];
break;
}
}
for(int i=;i<len;i++)
s1[i]=s[i+ans1];
reverse(str,str+len);
for(int i=;i<len;i++){
s[i]=str[i];
s[i+len]=str[i];
}
s[n]=;
build_sa();
getHeight();
// printf("%s\n",s);
// for(int i=0;i<n;i++)
// printf("%d ",sa[i]);
// printf("\n");
// for(int i=0;i<n;i++)
// printf("%d ",height[i]);
// printf("\n");
for(int i=n-;i>=;i--){
if(sa[i]<len){
ans2=sa[i];
if(height[i]<=len)
break;
}
}
for(int i=;i<len;i++){
s2[i]=s[i+ans2];
}
s2[len]=;
int ok=;
for(int i=;i<len;i++){
if(s1[i]>s2[i]){
ok=;
break;
}
if(s1[i]<s2[i]){
ok=-;
break;
}
}
ans2=len-ans2-;
ans1++,ans2++;
//printf("%d %d %d\n",ans1,ans2,ok);
if(ok>){
printf("%d 0\n",ans1);
}else if(ok<){
printf("%d 1\n",ans2);
}else{
if(ans2<ans1){
printf("%d 1\n",ans2);
}else{

【HDU - 5442】Favorite Donut 【最大表示法+KMP/后缀数组】的更多相关文章

  1. hdu 5442 Favorite Donut 最大表示法+kmp

    题目链接 给你一个字符串, 然后把他想象成一个环. 从某一个地方断开,然后逆时针或顺时针, 都可以形成一个字符串, 求字典序最大的那种. 输出断开位置以及是顺时针还是逆时针. 如果两个一样, 输出位置 ...

  2. HDU 5442——Favorite Donut——————【最大表示法+kmp | 后缀数组】

    Favorite Donut Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  3. Hdu 5442 Favorite Donut (2015 ACM/ICPC Asia Regional Changchun Online 最大最小表示法 + KMP)

    题目链接: Hdu 5442 Favorite Donut 题目描述: 给出一个文本串,找出顺时针或者逆时针循环旋转后,字典序最大的那个字符串,字典序最大的字符串如果有多个,就输出下标最小的那个,如果 ...

  4. HDU 5442 Favorite Donut(暴力 or 后缀数组 or 最大表示法)

    http://acm.hdu.edu.cn/showproblem.php?pid=5442 题意:给出一串字符串,它是循环的,现在要选定一个起点,使得该字符串字典序最大(顺时针和逆时针均可),如果有 ...

  5. hdu 5442 Favorite Donut 后缀数组

    Favorite Donut Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid ...

  6. luogu 2463 [SDOI2008]Sandy的卡片 kmp || 后缀数组 n个串的最长公共子串

    题目链接 Description 给出\(n\)个序列.找出这\(n\)个序列的最长相同子串. 在这里,相同定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串. 思路 参考:hzwe ...

  7. POJ2406 Power Strings(KMP,后缀数组)

    这题可以用后缀数组,KMP方法做 后缀数组做法开始想不出来,看的题解,方法是枚举串长len的约数k,看lcp(suffix(0), suffix(k))的长度是否为n- k ,若为真则len / k即 ...

  8. POJ 2406 KMP/后缀数组

    题目链接:http://poj.org/problem?id=2406 题意:给定一个字符串,求由一个子串循环n次后可得到原串,输出n[即输出字符串的最大循环次数] 思路一:KMP求最小循环机,然后就 ...

  9. POJ-3450 Corporate Identity (KMP+后缀数组)

    Description Beside other services, ACM helps companies to clearly state their “corporate identity”, ...

随机推荐

  1. spring cloud feign 接口继承以及参数传递的问题

    1. 优势     可以使用maven 进行访问,实现代码的共享,减少跨服务调用服务编写的问题   2. 使用      定义接口 publicinterfaceIUserService{ @Requ ...

  2. Java变量类型之间的转换

    int i; String s="134"; 1)String转换成int i=Integer.parseInt(s); 2)int转换成String(其他类型转String,都可 ...

  3. SecureCRT导入已有会话

    如果别人有完整的环境信息,我们想拿过来,怎么导入?或者别人想要我的会话配置信息,怎么导出?对SecureCRT这个工具来说很easy,根本不需要去找什么导入.导出按钮,直接文件操作. 假如我的Secu ...

  4. xshell 提示 继续使用此程序必须应用到最新的更新或使用新版本 的解决方案

    当打开正在使用的xshell后,提示“继续使用此程序必须应用到最新的更新或使用新版本 ”  是因为我们正在使用的是xshell5 版本,需要我们再安装一个xshell6 版本 我个人使用的是家庭/教育 ...

  5. CFile用法(转)

    一.各种关于文件的操作在程序设计中是十分常见,如果能对其各种操作都了如指掌,就可以根据实际情况找到最佳的解决方案,从而在较短的时间内编写出高效的代码,因而熟练的掌握文件操作是十分重要的.本文将对Vis ...

  6. Go的List操作上的一个小“坑”

    转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/ 一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂 ...

  7. net start mongodb发生系统错误2 系统找不到指定的文件

    安装mongodb时, 将mongodb 作为系统服务启动 net start mongodb,报错发生系统错误2 系统找不到指定的文件 . 查找原因是因为,系统服务的可执行文件地址有误. 修改服务地 ...

  8. 关于不同应用程序存储IO类型的描述

    介绍 存储系统作为数据的载体,为前端的服务器和应用程序提供读写服务.存储阵列某种意义上来说,是对应用服务器提供数据服务的后端“服务器”.应用服务器对存 储系统发送数据的“读”和“写”的请求.然而,不同 ...

  9. webpack快速入门(二):使用入门

    继续之前请确认你已经安装了nodejs 安装.初始化: 然后找个目录新建名为webpack-demo的文件夹,然后在命令行下进入该目录,执行以下命令: npm init -y npm install ...

  10. linux环境下搭建MySQL

    linux下搭建mysql的方式很多,网上也详解了很多种搭建方式,有直接yum的.有rpm的..总之,“坑”是层出不穷,有相关文件依赖性.权限.GPG keys等等. 本人也在今天搭建了一下.是出“坑 ...