题意:给定一个由小写字母组成的长度为 n 的字符串,首尾相连,可以从任意一个字符开始,顺时针或逆时针取这个串(长度为 n),求一个字典序最大的字符串的开始字符位置和顺时针或逆时针。如果有多个字典序最大的字符串,优先选择开始位置靠前的,如果开始位置相同,优先选择顺时针。

这种字符串的问题,第一反应是后缀数组,为了达到首尾相连的目的,所以先复制了一个两倍长的该字符串,然后再将串倒置,也弄成两倍长度,得到顺逆时针的两倍长的串,并对这两个字符串分别做后缀数组,得到 sa 数组(该串字典序第几小的后缀的开始字符是第几个)由于字符串的后缀长度必然不等,因此所有后缀都有确定的名次。

由于我们需要的是该串的循环n个串,所以对于每个 2*n 的串,它的后缀中我们需要的只有前 n 个,而每个串我们需要的也只有它的前 n 个字符,那么就出现了有可能有多个后缀的前 n 个字符是相同的,但是由于后缀的存在,使这些串的名次就有了差别。因此 sa 数组中我们得到的字典序最大的一个串,它的前 n 个字符只能确定是字典序最大的其中之一,因此我们就需要在 2*n 长度的串中找到第一个符合我们要求的串。所以我从得到的字典序最大的串中取出前 n 个字符,用这个串作为模式串在 2*n 串中 KMP 。

在顺时针的串中匹配到开始位置最靠前的第一个相同的串,而因为逆时针的串是将原串的所有字符导致,所以在逆时针串中开始位置越靠前,则它在原串中的开始位置就越靠后,因此我们需要KMP匹配找出的就是在 2*n 串中开始位置最靠后并且在 n 前的一个相同串。

最后再将得到的两个串比较他们的各个情况,输出最符合要求的一个。

恩,rank竟然变成了关键字,导致我当时CE了一发。

后来在被问到的时候我仔细再想了一下,觉得顺时针貌似并不需要用KMP,因为多个前 n 个字符相同的后缀,由于开始位置靠前的后缀长度会更长,所以字典序就会更大,所以我们取一个字典序最大的后缀,它在前 n 个字符相同的后缀串中开始位置也应该是更靠前的,所以我们用后缀数组得到的字典序最大的串就应该是我们需要的一个串,暂时我还没有想到反例。

但是逆时针却必须要匹配一下,因为字典序最大的,在 2*n 的串中开始位置更靠前,但在原串中开始位置就会越靠后,所以就要匹配得到在 2*n 串中最靠后的一个。例子就是 abcabc ,逆时针取的时候字典序最大的后缀开始位置是原串中的最后一个 c ,因此我们需要找出第三个字符 c 。所以我用了KMP。

但是据说有个做法是最小表示法,然而我并不知道那是什么,所以我还是用后缀数组+KMP过的Orz……

 #include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int MAXN=; int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
int rk[MAXN],height[MAXN];
void build_sa(int s[],int n,int m)
{
int i,j,p,*x=t1,*y=t2;
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[i]=s[i]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[i]]]=i;
for(j=;j<=n;j<<=)
{
p=;
for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小
for(i=;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[y[i]]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=;x[sa[]]=;
for(i=;i<n;i++)
x[sa[i]]=y[sa[i-]]==y[sa[i]] && y[sa[i-]+j]==y[sa[i]+j]?p-:p++;
if(p>=n)break;
m=p;//下次基数排序的最大值
}
} void getHeight(int s[],int n)
{
int i,j,k=;
for(i=;i<=n;i++)rk[sa[i]]=i;
for(i=;i<n;i++)
{
if(k)k--;
j=sa[rk[i]-];
while(s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
} char str[MAXN];
int s0[MAXN];
int s1[MAXN];
int ans0[MAXN];
int ans1[MAXN];
int pp1[MAXN],pp0[MAXN]; int check(int n){
for(int i=;i<n;++i){
if(ans0[i]<ans1[i])return ;
else if(ans0[i]>ans1[i])return ;
}
return -;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
scanf("%s",str);
for(int i=;i<=n;i++)s0[i]=str[i]-'a'+;
for(int i=;i<=n;i++)s0[n+i]=str[i]-'a'+;
s0[*n]=;
/* for(int i=0;i<=2*n;++i)printf("%d ",s0[i]);
printf("\n");*/
build_sa(s0,*n+,);
/* for(int i=0;i<=2*n;++i)printf("%d ",sa[i]);
printf("\n");*/
int p0,p1;
for(int i=*n;i>=;--i){
if(sa[i]<n){p0=sa[i];break;}
}
for(int i=;i<n;++i){
ans0[i]=s0[p0+i];
// printf("%d ",ans0[i]);
}
/* printf("\n");
printf("\n");*/ for(int i=,j=n-;i<n;i++,j--)s1[j]=str[i]-'a'+;
for(int i=,j=n-;i<n;i++,j--)s1[n+i]=str[j]-'a'+;
s1[*n]=;
/* for(int i=0;i<=2*n;++i)printf("%d ",s1[i]);
printf("\n");*/
build_sa(s1,*n+,);
/* for(int i=0;i<=2*n;++i)printf("%d ",sa[i]);
printf("\n");*/
for(int i=*n;i>=;--i){
if(sa[i]<n){p1=sa[i];break;}
}
for(int i=;i<n;++i){
ans1[i]=s1[p1+i];
// printf("%d ",ans1[i]);
} /* printf("\n");
printf("\n");
*/
int cc=check(n);
// printf("c%d\n",cc);
if(cc==-){
int i,j;
pp0[]=pp0[]=;
for(i=;i<n;++i){
j=pp0[i];
while(j&&ans0[i]!=ans0[j])j=pp0[j];
pp0[i+]=ans0[i]==ans0[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s0[i]!=ans0[j])j=pp0[j];
if(s0[i]==ans0[j])j++;
if(j==n){
p0=i-n+;
break;
}
}
pp1[]=pp1[]=;
for(i=;i<n;++i){
j=pp1[i];
while(j&&ans1[i]!=ans1[j])j=pp1[j];
pp1[i+]=ans1[i]==ans1[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s1[i]!=ans1[j])j=pp1[j];
if(s1[i]==ans1[j])j++;
if(j==n){
if(i-n+<n)p1=i-n+;
}
}
p1=n-(p1+);
// printf("p0:%d p1:%d\n",p0,p1);
if(p0<p1){
printf("%d 0\n",p0+);
}
else if(p0>p1){
printf("%d 1\n",p1+);
}
else printf("%d 0\n",p0+); }
else if(cc==){
int i,j;
pp0[]=pp0[]=;
for(i=;i<n;++i){
j=pp0[i];
while(j&&ans0[i]!=ans0[j])j=pp0[j];
pp0[i+]=ans0[i]==ans0[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s0[i]!=ans0[j])j=pp0[j];
if(s0[i]==ans0[j])j++;
if(j==n){
p0=i-n+;
break;
}
}
printf("%d 0\n",p0+);
}
else if(cc==){
int i,j;
pp1[]=pp1[]=;
for(i=;i<n;++i){
j=pp1[i];
while(j&&ans1[i]!=ans1[j])j=pp1[j];
pp1[i+]=ans1[i]==ans1[j]?j+:;
}
j=;
for(int i=;i<*n;++i){
while(j&&s1[i]!=ans1[j])j=pp1[j];
if(s1[i]==ans1[j])j++;
if(j==n){
if(i-n+<n)p1=i-n+;
// p0=i-n+1;
}
}
p1=n-(p1+);
printf("%d 1\n",p1+);
}
}
return ;
}

hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?的更多相关文章

  1. hdu5443(2015长春赛区网络赛1007)暴力

    题意:给了一个数列,有多个询问,每个询问求某个区间内的最大值 数列长度 1000,询问个数 1000,静态,并不需要RMQ这些,直接暴力 n2 查找每个询问区间取最大值就行了. #include< ...

  2. hdu5441(2015长春赛区网络赛1005)类最小生成树、并查集

    题意:有一张无向图,一些点之间有有权边,某条路径的值等于路径上所有边的边权的最大值,而某个点对的值为这两点间所有路径的值的最小值,给出多个询问,每个询问有一个值,询问有多少点对满足其值小于等于询问值. ...

  3. hdu5438(2015长春赛区网络赛1002)拓扑序+DFS

    题意:给出一张无向图,每个节点有各自的权值,问在点数为奇数的圈中的点的权值总和是多少. 通过拓扑序的做法标记出所有非圈上的点,做法就是加每条边的时候将两点的入度都加一,然后将所有度数为1的点入队,删去 ...

  4. hdu 4274 2012长春赛区网络赛 树形dp ***

    设定每个节点的上限和下限,之后向上更新,判断是否出现矛盾 #include<cstdio> #include<iostream> #include<algorithm&g ...

  5. hdu 4277 2012长春赛区网络赛 dfs+hashmap ***

    hashmap判重大法好 #include<cstdio> #include<iostream> #include<algorithm> #include<c ...

  6. hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***

    新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...

  7. hdu 4272 2012长春赛区网络赛 dfs暴力 ***

    总是T,以为要剪枝,后来发现加个map就行了 #include<cstdio> #include<iostream> #include<algorithm> #in ...

  8. Largest Point (2015沈阳赛区网络赛水题)

    Problem Description Given the sequence A with n integers t1,t2,⋯,tn. Given the integral coefficients ...

  9. 2017青岛赛区网络赛 Smallest Minimum Cut 求最小割的最小割边数

    先最大流跑一遍 在残存网络上把满流边容量+1 非满流边容量设为无穷大 在进行一次最大流即可 (这里的边都不包括建图时用于反悔的反向边) #include<cstdio> #include& ...

随机推荐

  1. <select>标签使用方法

    前台页面: <form id="form1" runat="server"> <select runat="server" ...

  2. 数组的filter方法

    filter()函数用于过滤序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素. eg: var arr=[10,11,12,13,14 ...

  3. poj3126 筛素数+bfs

    //Accepted 212 KB 16 ms //筛素数+bfs #include <cstdio> #include <cstring> #include <iost ...

  4. 使用sslsplit嗅探tls/ssl连接

    首先发一个从youtube弄到的sslsplit的使用教程 http://v.qq.com/page/x/k/s/x019634j4ks.html 我最近演示了如何使用mitmproxty执行中间人攻 ...

  5. fwrite错误

    使用fwrite出错 f:\dd\vctools\crt_bld\self_x86\crt\srt\write.cline:69expression:_osfile(fh)&FOPEN 使用w ...

  6. phpunit+selenium环境搭建

    这个环境搭建遇到了挺多麻烦,最终还是没能自己解决,幸好有同事“青蛙”的帮忙解决了这个问题!在这里把本人亲测步骤给大家列一下,希望给大家提供方便! 安装pear: Go-pear.phar下载地址:ht ...

  7. Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

    Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK fla ...

  8. ERP存储过程的调用和树形菜单的加载(四)

    引用:DAL:System.Data.SqlClient;System.Data; namespace CommTool { public class SqlComm { /// <summar ...

  9. windows 命令修改IP

    修改ip: netsh -c interface ip set address name="本地连接" source=static addr=192.168.11.100 mask ...

  10. iOS-微信支付平台

    微信支付1:去微信开放平台注册应用https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN&token=2c0f ...