题意

给出一个长度为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. 怎么安装Docker CE 17( Centos 7)

    Docker CE for Centos 7 yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manage ...

  2. java的try-with-resource机制

    在java7之后可以使用try(resource1, resource2){...}这样声明之后,在try{}执行完成之后或者抛异常跳出,都会调用reouce1.close(),resource2.c ...

  3. display的flex属性使用详解

    flex的兼容性在pc端还算阔以,但是在移动端,那就呵呵了.今天我们只是学习学习,忽略一些不重要的东西. 首先flex的使用需要有一个父容器,父容器中有几个items. 父容器:container 属 ...

  4. sql分割字符串详解

    create function f_split(@c varchar(2000),@split varchar(2)) returns @t table(col varchar(20)) as beg ...

  5. MongoDB在windows平台分片集群部署

    本文转载自:https://www.cnblogs.com/hx764208769/p/4260177.html 前言-为什么我要使用mongodb 最近我公司要开发一个日志系统,这个日志系统包括很多 ...

  6. redisTemplate 方法

    ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-redis.xml&qu ...

  7. php网站环境无法上传的解决办法?

    一. 检查网站目录的权限.二. php.ini配置文件php.ini中影响上传的有以下几处:file_uploads 是否开启 on 必须开启是否允许HTTP文件上传post_max_size = 8 ...

  8. 关于mongodb ,redis,memcache之间见不乱理还乱的关系和作用

    先说我自己用的情况: 最先用的memcache ,用于键值对关系的服务器端缓存,用于存储一些常用的不是很大,但需要快速反应的数据 然后,在另一个地方,要用到redis,然后就去研究了下redis. 一 ...

  9. python学习笔记(十一):网络编程

    一.python操作网络,也就是打开一个网站,或者请求一个http接口,使用urllib模块. urllib模块是一个标准模块,直接import urllib即可,在python3里面只有urllib ...

  10. 超简单让ubuntu开启wifi热点(亲测16.04与14.04可用)

    今天教大家一个简单方法让ubuntu发散wifi热点给手机或者其他设备使用. 首先,创建一个普通的热点,点击右上角的网络,然后选择下拉菜单中的编辑连接,然后出现以下界面. 然后点击增加,连接类型选接W ...