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& ...
随机推荐
- 使用OCI向Oracle插入Geometry数据
使用C/C++操作Oracle数据库,使用OCI可谓是最强大,当然也是最难的方式.Oracle是一个功能复杂而强大的数据库,它可以很好的支持空间数据(Oracle spatial).如何使用OCI向O ...
- arm裸机驱动错误总结
错误001:
- [windows驱动]windows8.1驱动调试前戏
人们都说在干正事之前,得先做足前戏才会爽,我一直很认同这个观点,下面我来总结下进行windows8.1的WDK调试所要做的准备工作. 软件安装: 1.VS2013. 2.WDK8.1 3.Window ...
- 新发布GoldenGate 12c版本中的主要特性
业界领先的实时数据集成工具GoldenGate现在可以帮助企业在传统数据库和云平台.大数据平台之间进行实时复制.新的OGG 12c支持更多的异构数据库和大数据平台,进一步提升可管理性和对混合云 ...
- WIN中SharePoint Server 2010 入门安装部署详解
目前流行的原始安装文件基本都是这样的:Windows Server 2008 R2+SQL Server 2008R2+SharePoint Server 2010 这个初始环境原本也无可厚非 ...
- iOS APP提交上架最新流程
时隔1年又让我鼓捣iOS,刚接手就是上架,经验值为0的我,虽然内心是拒绝的,但还是要接受这项任务滴!也就是在被拒后重新审核,再改在提交...这样反复的过程中也对上架流程熟悉了好多,写篇帖子 ...
- poj蚂蚁问题
问题描述: n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行.当蚂蚁爬到竿子的端点时就会掉落.由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向 爬回去.对于每只蚂蚁,我们知道它距离竿子左 ...
- ubuntu下修改mysql默认字符编码出现的Job failed to start解决办法
ubuntu下修改mysql默认字符编码出现的Job failed to start解决办法 前几天卸掉了用了好多年的Windows,安装了Ubuntu12.04,就开始各种搭环境.今天装好了MySQ ...
- android:windowSoftInputMode及其他部分属性用法
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 今天我们来讲讲android:windoSoftInputMode的用法,许多同学会为软键盘的弹出. ...
- 【JOJO】真男人-坚不可摧
DIO,你输给我的原因只有一个! 那就是,你惹怒了我! http://www.bilibili.com/video/av461689/