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& ...
随机推荐
- xlistview的java(头)
package com.bwie.xlistviews; import com.bwie.test.R; import android.content.Context;import android.u ...
- hadoop shell 操作命令
shell操作命令: hdfs的路径,在core-site.xml中定义 <property> <name>fs.default.name</name> <v ...
- 发布Restful服务时出现IIS 指定了身份验证方案错误时的解决方案(IIS specified authentication schemes)
发布RESTful服务,当访问.svc文件时出现如下错误时: IIS 指定了身份验证方案“IntegratedWindowsAuthentication, Anonymous”,但绑定仅支持一种身份验 ...
- (三)获取iphone的IMSI
今天的任务是 iPhone上怎样获取 imsi 信息 来判断所属运营商,资料找了很久!总体有两种方案,但是其中一种好像不行 这里我都记录下来吧: 1: 这是使用coreTelephony.framew ...
- Ubuntu 14.10 下安装Synergy,不同电脑之间公用一套键盘鼠标
因为工作时候有多台电脑放在一起,如果每个用一套键盘鼠标很是不方便,所以希望能够不用电脑之间公用一套键盘鼠标. Synergy可以实现不同电脑之间公用一套键盘鼠标,并且支持简单的复制粘贴.很好用. 它还 ...
- druid简介
Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser. 支持的数据库 Druid支持所有JDBC兼容 ...
- hdu 2064
ps:分析发现,要移动n个到最左端,首先要移动n-1个从A到C,然后从C到A,然后再从A到C,然后中间是把大盘从A到C,两步.递推公式自然就是a[n]=3*a[n-1]+2 代码: #include ...
- javascript的词法分析
-.arguments的解释: 1.是一个对象,是一个长的很像数组的对象 二.arguments内容是什么? 1.arguments是函数运行时的实参列表 2.arguments收集的“所有”的实参, ...
- Redis - 密码配置和主从复制
使用config set命令修改requirepass参数配置Redis密码config set requirepass password 也可以通过配置文件修改密码,重启后生效. 克隆虚拟机,分别运 ...
- 6、SQL基础整理(日期时间数据类型,转换函数)
日期时间数据类型 *系统常量: @@DATEFIRST(返回当前时间) DATEADD 增加时间 语法:DATEADD (datepart , number , date ) select DATEA ...