题意

给出一个长度为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. fatal: The remote end hung up unexpectedly解决办法

    $ git config --global http.postBuffer 2428000 git config http.postBuffer 524288000 配置完成后 git pull一下, ...

  2. Android模糊图像

    在Android中.我们能够实现非常多非常酷的处理图片的效果. 在2014年某次会议的讲演<图像的魔力>中,我介绍了当中的一部分. 当中的一项技术是怎样模糊图像.演示样例代码是使用Rend ...

  3. bower.json 的版本范围

    bower.json 的版本范围 有小伙伴问 ~2.2.0 什么意思. 而且在git 的tags 中没有了 2.2.0 版本,怎么样? 实际上 ~2.2.0 的意思是 >=2.2.0 <2 ...

  4. 数据双向绑定页面无反应(angularjs)

    问题引入 使用 angularjs进行过一段时间的开发后,基本上都会遇到一个这样的坑:页面进行了双向数据绑定,控制层的数据也已经改变了,但是视图层的数据却没有改变. 其实造成这个问题的原因大致分为以下 ...

  5. Renesas APIs ***

    一个线程,强行结束另外一个线程,并将其挂起: static void SuspendTask(TX_THREAD *thread) { UINT status = ; UINT state; stat ...

  6. TCP/IP协议:最大传输单元MTU 和 最大分节大小MSS

    MTU = MSS + TCP Header + IP Header. mtu是网络传输最大报文包. mss是网络传输数据最大值. MTU:maximum transmission unit,最大传输 ...

  7. 示例文件下载demo

    页面: 后台: package com.js.ai.modules.shwindow.util; import java.io.BufferedInputStream; import java.io. ...

  8. OD 实验(一) - 修改程序标题

    需要修改的程序 把 I love fishc.com 修改为 hello world sch01ar 用 OD 打开程序 在程序入口处开始一直按 F8 运行程序,看看在哪里弹出对话框 运行到该地址的时 ...

  9. Newtonsoft.Json[C#]

    C# Newtonsoft.Json JsonSerializerSettings配置序列化操作 https://blog.csdn.net/u011127019/article/details/72 ...

  10. lunix,命令集锦

    1. ls命令 ls命令是列出目录内容(List Directory Contents)的意思.运行它就是列出文件夹里的内容,可能是文件也可能是文件夹. ? 1 2 3 4 5 6 7 root@te ...