HDU 5442 后缀自动机+kmp
题目大意:
给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针
比赛一直因为处理最小位置出错,一结束就想明白了。。。真是作孽
这里正向后缀自动机跑一遍最大的,这样得到的位置肯定是最小的
而逆时针最大就反向重建后缀自动机再跑一遍最大的,但这样因为后缀自动机跑出的位置是最小的,但返回来就变成最大的位置了
如果存在更小的位置,那么就相当于可以从开头拎出一段移到末尾,那么必然是产生一个循环节,这个长度可以利用kmp来处理
#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 = ;
}
}; SamNode sam[N] , *root , *last;
int cnt; void init(){
cnt = ;
memset(sam , , sizeof(sam));
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;
}
}
}
ull _hash = ; int _next[N];
int s[N];
void get_next(int *s , int n)
{
_next[] = _next[] = ;
for(int i=; i <n ; i++){
int j=_next[i-];
while(j && s[j+]!=s[i]) j =_next[j];
_next[i] = s[j+]==s[i]?j+:;
}
} int solve(int len)
{
SamNode *cur = root;
for(int i= ; i<len ; i++){
for(int j= ; j>= ; j--){
if(cur->son[j]){
s[i] = 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 = solve(len);
ret2 = len-ret2+;
// cout<<"here: "<<ret1<<" "<<ret2<<endl;
get_next(s , n);
int del = n-_next[n-]-;
// cout<<"try: "<<del<<" "<<_next[n-1]<<endl;
if(n%del==){
while(ret2>del) ret2-=del;
}
// 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 ;
}
SAM+kmp
后来终于受人指点知道了直接在后缀自动机上找到最后一个位置得到的最大字典序怎么求了,这样就不用求kmp了
后缀自动机上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 后缀自动机+kmp的更多相关文章
- HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)
http://acm.hdu.edu.cn/showproblem.php?pid=5442 题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样 ...
- HDU 4436 (后缀自动机)
HDU 4436 str2int Problem : 给若干个数字串,询问这些串的所有本质不同的子串转换成数字之后的和. Solution : 首先将所有串丢进一个后缀自动机.由于这道题询问的是不同的 ...
- HDU 4622 (后缀自动机)
HDU 4622 Reincarnation Problem : 给一个串S(n <= 2000), 有Q个询问(q <= 10000),每次询问一个区间内本质不同的串的个数. Solut ...
- HDU 4416 (后缀自动机)
HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...
- [BZOJ3796]Mushroom追妹纸:后缀自动机+KMP
分析 这道题有个\(O(n)\)的后缀自动机做法,感觉很好理解就在这说一下. 先对\(s1\)和\(s2\)求最长公共子串,对于\(s2\)的每一个下标\(i\),求一个\(f[i]\)表示以\(s2 ...
- hdu 6208(后缀自动机、或者AC自动机
题意:给你n个字符串,问你是否存在一个字符串可以从中找到其他n-1个字符串. 思路:其实很简单,找到最长的那个字符串对他进行匹配,看是否能匹配到n-1个字符串. 可以用AC自动机或者后缀自动机做,但是 ...
- Boring counting HDU - 3518 后缀自动机
题意: 对于给出的字符串S, 长度不超过1000, 求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次 题解: 将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出 ...
- Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置
题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...
- str2int HDU - 4436 后缀自动机求子串信息
题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...
随机推荐
- 使用kaptcha生成验证码
原文:http://www.cnblogs.com/xdp-gacl/p/4221848.html kaptcha是一个简单好用的验证码生成工具,通过配置,可以自己定义验证码大小.颜色.显示的字符等等 ...
- maven Connection refused: connect
现象: 本地可以访问错误提示中的地址.但使用maven无法下载jar包. 环境: 浏览器上网需要使用代理 解决方法: 设置成正常代理可以.具体方法可以下载一个代理工具.只要IE配置成能直接访问http ...
- google_apactest_round_A_problem_D
先尝试过小数据 题目 有8张卡牌,每个卡牌都可以有不同的等级,每个卡牌的不同等级具有不同的攻击力,可以通过花钱给卡牌充值从而升级,且每次只能升一级,比如可以花1个硬币将卡牌2从1级升级到2级,同时卡牌 ...
- iOS开发 判断用户是否开启了定位
- (BOOL)achiveUserLocationStart { CLAuthorizationStatus status = [CLLocationManager authorizationSta ...
- SVN使用汇总
SVN项目管理文件夹:Tag/Branch/Trunk Trunk:在我经历的开发中,新建Trunk意味着对旧Trunk的一个保留,同时在新的Trunk中可以进行新功能的开发及对已有功能进行完善: B ...
- MyEclipse/Eclipse中XML文件的格式化配置
Eclipse中XML文件的格式化配置 MyEclipse: 这一步的配置是使格式化的效果为控件的每个属性配置占一行.进入 Window/Preferences,展开到 XML/XML Resourc ...
- 让页面滑动流畅得飞起的新特性:Passive Event Listeners
版权声明:本文由陈志兴原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/153 来源:腾云阁 https://www.qclo ...
- javaWeb1 tomcat
tomcat使用常见问题: 1.闪退: 原因:tomcat 软件是由java语言开发的,当它启动时,会默认到系统 的环境变量中查找 JAVA_HOME 的变量.找它的目的时tomcat 启动 时需要j ...
- python 练习 2
#!/usr/bin/python # -*- coding: utf-8 -*- from random import shuffle class caigame: win=False flag=F ...
- [redis] Redis 配置文件置参数详解
################################ 基础配置 ################################# #daemonize no 默认情况下, redis 不 ...