http://acm.hdu.edu.cn/showproblem.php?pid=5442

题目大意:

给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针

后缀自动机上s记录达到的最长的位置,如果不更新,那么必然一次跑完得到的是最小位置,那么为了得到最大,之前更新每一个节点中的s,只有儿子位置上的能更新父亲

所以先将后缀自动机拓扑排序,然后从后往前,不断将父亲的s更新成更大的s

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define M 26
#define N 80100
#define ull unsigned long long
char str[N] , tmp[N];
int n , num[N];
queue<int> Q; struct SamNode{
SamNode *son[M] , *f;
int l , s;
void init(){
for(int i= ; i<M ; i++) son[i] = NULL;
f = NULL;
l = s = ;
}
}*b[N]; SamNode sam[N] , *root , *last;
int cnt; void init(){
cnt = ;
sam[].init();
root = last = &sam[];
} void add(int x){
sam[cnt+].init();
SamNode *p = &sam[++cnt] , *jp=last;
/*
这里p->s = jp->s+1写成p->s = p->l也是一样的,因为对于每次当前的last来说,
l和s的值是一样的,因为每次当前的last都是处于字符串的位置上的
数,不是额外添加的节点
*/
p->l = jp->l+; p->s = jp->s+;
last = p;
for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
if(!jp) p->f=root;
else{
if(jp->l+ == jp->son[x]->l) p->f = jp->son[x];
else{
sam[cnt+].init();
SamNode *r = &sam[++cnt] , *q = jp->son[x];
*r=*q;
r->l = jp->l+ ; r->s = p->l;
q->f = p->f = r;
for(; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
} int solve(int len)
{
SamNode *cur = root;
for(int i= ; i<len ; i++){
for(int j= ; j>= ; j--){
if(cur->son[j]){
cur = cur->son[j];
break;
}
}
}
int ret = cur->s-len+; return ret;
} int solve1(int len)
{
memset(num , , sizeof(num));
for(int i= ; i<=cnt ; i++) num[sam[i].l]++;
for(int i= ; i<=len* ; i++) num[i] += num[i-];
for(int i= ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
for(int i=cnt- ; i>= ; i--){
b[i]->f->s = max(b[i]->f->s , b[i]->s);
}
SamNode *cur = root;
for(int i= ; i<len ; i++){
for(int j= ; j>= ; j--){
if(cur->son[j]){
cur = cur->son[j];
break;
}
}
}
int ret = cur->s-len+;
return ret;
} int main() {
// freopen("a.in" , "r" , stdin);
// freopen("out.txt" , "w" , stdout);
int T;
scanf("%d" , &T);
while(T--){
scanf("%d" , &n);
scanf("%s" , str);
int len = n;
init();
for(int i= ; i<len ; i++)
str[len+i] = str[i];
for(int i= ; i<len* ; i++)
add(str[i]-'a');
// for(int i=0 ; i<2*n ; i++) cout<<str[i];
//cout<<endl;
int ret1 = solve(len); for(int i= ; i<len ; i++){
tmp[len-i-] = str[i];
}
for(int i= ; i<len ; i++){
tmp[len+i] = tmp[i];
} init();
for(int i= ; i<len*- ; i++)
add(tmp[i]-'a');
int ret2 = len-solve1(len)+; // cout<<"here: "<<ret1<<" "<<ret2<<endl;
// cout<<ret1<<" "<<ret2<<endl;
int i , j , cnt , pos , wise=-;
for(i=ret1- , j=ret2+len- , cnt= ; cnt<len ; cnt++ , i++ , j--){
// cout<<cnt<<" "<<i<<" "<<j<<" "<<str[i]<<" "<<str[j]<<endl;
if(str[i]>str[j]){wise=;pos=ret1;break;}
else if(str[i]<str[j]){wise=;pos=ret2;break;}
}
if(wise==-){
if(ret1<ret2) pos = ret1 , wise = ;
else if(ret1>ret2) pos = ret2 , wise = ;
else pos=ret1 , wise=;
// cout<<"in: "<<endl;
}
printf("%d %d\n" , pos, wise);
}
return ;
}

HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)的更多相关文章

  1. HDU 5442 后缀自动机+kmp

    题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针 比赛一直因为处理最小位置出错,一结束就想 ...

  2. hdu 6208(后缀自动机、或者AC自动机

    题意:给你n个字符串,问你是否存在一个字符串可以从中找到其他n-1个字符串. 思路:其实很简单,找到最长的那个字符串对他进行匹配,看是否能匹配到n-1个字符串. 可以用AC自动机或者后缀自动机做,但是 ...

  3. HDU 4436 (后缀自动机)

    HDU 4436 str2int Problem : 给若干个数字串,询问这些串的所有本质不同的子串转换成数字之后的和. Solution : 首先将所有串丢进一个后缀自动机.由于这道题询问的是不同的 ...

  4. HDU 4622 (后缀自动机)

    HDU 4622 Reincarnation Problem : 给一个串S(n <= 2000), 有Q个询问(q <= 10000),每次询问一个区间内本质不同的串的个数. Solut ...

  5. HDU 4416 (后缀自动机)

    HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...

  6. Boring counting HDU - 3518 后缀自动机

    题意: 对于给出的字符串S, 长度不超过1000, 求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次 题解: 将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出 ...

  7. Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置

    题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...

  8. str2int HDU - 4436 后缀自动机求子串信息

    题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...

  9. 不在B中的A的子串数量 HDU - 4416 (后缀自动机模板题目)

    题目: 给定一个字符串a,又给定一系列b字符串,求字符串a的子串不在b中出现的个数. 题解: 先将所有的查询串放入后缀自动机(每次将sam.last=1)(算出所有子串个数) 然后将母串放入后缀自动机 ...

随机推荐

  1. JS作用域理解(声明提升)

    1.JS解析步骤: a.预解析 将变量声明提升: 将函数声明及函数内容提升,可以理解成原来位置的函数在解析代码时已经提到代码初始位置: 块内的变量声明和函数声明也会被提升,例如if语句 遇到重名,只留 ...

  2. slice,substr和substring方法的区别

    slice(start[,end])方法需要提供至少一个整数参数,作用是返回从start的位置开始到end位置的字符子串.当参数start为负数的时候他将从字符串尾部开始计算,当end没有指定时,en ...

  3. 【转】C语言中DEFINE简介及多行宏定义

    要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等. 在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定 ...

  4. mysql json格式数据处理

    1.查询字段所对应的值: SELECT c.result_http->"$.create_time",json_extract(c.result_http,"$.e ...

  5. GitLab服务器IP地址修改

    gitlab安装介绍:https://about.gitlab.com/downloads/#centos7 刚搭建好的gitlab在GitLab上新建一个项目test_gitlab,刚开始仓库地址是 ...

  6. SurfaceView实时绘图,视频流

  7. servlet及xml文件处理流程

    启动项目----会找到web.xml文件---跳转到默认jsp----页面重定向----转到xml.文件下 通过<servlet-mapping>映射找到<servlet>标签 ...

  8. 洛谷P2387 [NOI2014]魔法森林(lct维护最小生成树)

    题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,…,n,边标号为 1,2,3,…, ...

  9. 大数据hadoop分布式系统

    1>hadoop简介: Hadoop是一个开发和运行处理大规模数据的软件平台,是Apache的一个用java语言实现开源软件框架,实现在大量计算机组成的集群中对海量数据进行      分布式计算 ...

  10. MVC4 View 的呈现

    一 ActionResult: 1. EmptyResult: Action方法返回的ActionResult对象被ActionInvoker 调用以实现对当前请求的响应,不论Action方法是否具有 ...