hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?
题意:给定一个由小写字母组成的长度为 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 /最小表示法?的更多相关文章
- hdu5443(2015长春赛区网络赛1007)暴力
题意:给了一个数列,有多个询问,每个询问求某个区间内的最大值 数列长度 1000,询问个数 1000,静态,并不需要RMQ这些,直接暴力 n2 查找每个询问区间取最大值就行了. #include< ...
- hdu5441(2015长春赛区网络赛1005)类最小生成树、并查集
题意:有一张无向图,一些点之间有有权边,某条路径的值等于路径上所有边的边权的最大值,而某个点对的值为这两点间所有路径的值的最小值,给出多个询问,每个询问有一个值,询问有多少点对满足其值小于等于询问值. ...
- hdu5438(2015长春赛区网络赛1002)拓扑序+DFS
题意:给出一张无向图,每个节点有各自的权值,问在点数为奇数的圈中的点的权值总和是多少. 通过拓扑序的做法标记出所有非圈上的点,做法就是加每条边的时候将两点的入度都加一,然后将所有度数为1的点入队,删去 ...
- hdu 4274 2012长春赛区网络赛 树形dp ***
设定每个节点的上限和下限,之后向上更新,判断是否出现矛盾 #include<cstdio> #include<iostream> #include<algorithm&g ...
- hdu 4277 2012长春赛区网络赛 dfs+hashmap ***
hashmap判重大法好 #include<cstdio> #include<iostream> #include<algorithm> #include<c ...
- hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***
新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...
- hdu 4272 2012长春赛区网络赛 dfs暴力 ***
总是T,以为要剪枝,后来发现加个map就行了 #include<cstdio> #include<iostream> #include<algorithm> #in ...
- Largest Point (2015沈阳赛区网络赛水题)
Problem Description Given the sequence A with n integers t1,t2,⋯,tn. Given the integral coefficients ...
- 2017青岛赛区网络赛 Smallest Minimum Cut 求最小割的最小割边数
先最大流跑一遍 在残存网络上把满流边容量+1 非满流边容量设为无穷大 在进行一次最大流即可 (这里的边都不包括建图时用于反悔的反向边) #include<cstdio> #include& ...
随机推荐
- jsp福利哟
Servlet与JSP九大内置对象的关系 JSP对象 怎样获得 out->response.getWriter request ->Service方法中的req参数 response -& ...
- java基础之类与继承 详解
Java:类与继承 对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础.抽象.封装.继承.多态这四大特性都离不开类,只有存在类,才能体现面向对象编程的特点,今天我们就来了解一些类与继承的相关知 ...
- Project和Module的介绍
Project 和 Module 介绍 这两个概念是 IntelliJ IDEA 的必懂知识点之一,请务必要学会. 如果你是 Eclipse 用户,并且已经看了上面给的链接,那 IntelliJ ID ...
- 学习MVC的一些随笔简单记录
1 视图本身没有它所要显示的数据,视图的数据源始终是控制器 3 游戏的进行是模型的一部分,不是控制器的一部分 4 模型关于游戏是什么,在模型中封装游戏进行的逻辑,模型对用户界面一无所知,里面没有任何同 ...
- 2013年国庆节前51Aspx源码发布详情
Sky软件公司网站修正版源码 2013-9-30 [VS2010]源码描述:针对Sky软件公司网站源码进行修正.修改ckeditor引用问题,发布样式错误问题.vs2010直接编译.发布成功. 网站 ...
- 关于doctype
一:html文档类型 doctype为documentype 的简称,是在html页面中声明的XHTML或者HTML的文件类型,正确准确的文件类型的声明,才能使html标签以及CSS样式生效. 声明文 ...
- 码表由来:ascll码-Gbk2312-GBK-Unicode-UTF-8
码表ascll码-Gbk2312-GBK-Unicode-UTF-8, ascll是基本的标准码表,GB2312是中文码表,GBK是扩展之后的码表,Unicode是国际通用码表,UTF-8是优化后的U ...
- CentOS中配置LNMP环境打开提示File not found
在centos系统中配置好php环境了,但是发现能运行html页面并不能运行php文件了,这样我就在gg的帮助下一步不解决了,下面来看问题的具体解决过程. 安装之后测试发现,怎么Html能运行 ...
- hadoop环境搭建遇到问题集锦
1 在hadoop的bin目录下, 运行hadoop version命令,提示“hadoop:没有此命令” 解决办法: ./hadoop version或者$HADOOP_HOME/bin放在PAT ...
- 【LeetCode OJ】Best Time to Buy and Sell Stock II
Problem Link: http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ We solve this prob ...