POJ 1509 Glass Beads 后缀自动机 模板 字符串的最小表示

http://poj.org/problem?id=1509

后缀自动机其实就是一个压缩储存空间时间(对节点重复利用)的储存所有一个字符串所有子串的trie树,如果想不起来长什么样子可以百度一下找个图回忆,从0开始到任意一个点的串都是字符串的子串。 有一些很好用的性质。

字符串的最小表示就是把一个字符串首尾相连再从任意一个地方断开产生的字典序最小的字符串,这个题是求最小表示的开头字母在原字符串中的下标(从1开始)。

具体看实现吧,没什么可以解释的地方。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn=100010;
 9 char ch[maxn]={};
10 int siz;
11 int tot,la;
12 struct nod{
13     int sig[26];int f,len;
14     void cle(){f=-1,len=0;memset(sig,-1,sizeof(sig));}
15 }sam[maxn*2];
16 void fir(){tot=0;la=0;sam[0].cle();}
17 void add(int z){
18     int x=++tot;sam[x].cle();
19     int i=la;
20     sam[x].len=sam[la].len+1;
21     for(;i!=-1&&sam[i].sig[z]==-1;i=sam[i].f)
22         sam[i].sig[z]=x;
23     if(i==-1)sam[x].f=0;
24     else{
25         int nex=sam[i].sig[z];
26         if(sam[i].len+1==sam[nex].len)sam[x].f=nex;
27         else{
28             int y=++tot;sam[y].cle();
29             sam[y]=sam[nex];
30             sam[y].len=sam[i].len+1;
31             sam[x].f=sam[nex].f=y;
32             for(;i!=-1&&sam[i].sig[z]==nex;i=sam[i].f){
33                 sam[i].sig[z]=y;
34               }
35         }
36     }la=x;
37 }
38 int main(){
39     int T;scanf("%d",&T);
40     while(T-->0){
41         fir();
42         scanf("%s",ch);siz=strlen(ch);
43         for(int i=0;i<siz*2;++i)add(ch[i%siz]-‘a‘);
44         int p=0;
45         for(int i=0;i<siz;i++){
46             for(int j=0;j<26;j++){
47                 if(sam[p].sig[j]!=-1){p=sam[p].sig[j];break;}
48             }
49         }
50         printf("%d\n",sam[p].len-siz+1);
51     }
52     return 0;
53 }

原文地址:https://www.cnblogs.com/137shoebills/p/8531075.html

时间: 2024-10-11 12:47:39

POJ 1509 Glass Beads 后缀自动机 模板 字符串的最小表示的相关文章

POJ 1509 Glass Beads 后缀自动机

题目大意:给出一个环形的字符串,问从哪里开始是的这个字符串的字典序最小. 思路:最小表示法和后缀自动机的裸题,不过我是为了学后缀自动机才写的这个题,就没有去学最小表示法. 做法很简单,先建立一个后缀自动机,然后从根开始沿tranc指针从a->z走len次到达的点就是字典序最小的字符串的结尾点,求起始点只要减一下长度再+1即可. 对于后缀自动机的理解:http://wyfcyx.is-programmer.com/posts/76107.html CODE: #include <cstdio&g

[最小表示] poj 1509 Glass Beads

题目链接: http://poj.org/problem?id=1509 Glass Beads Time Limit: 3000MS   Memory Limit: 10000K Total Submissions: 2311   Accepted: 1343 Description Once upon a time there was a famous actress. As you may expect, she played mostly Antique Comedies most of

●POJ 1509 Glass Beads

题链: http://poj.org/problem?id=1509 题解: 给出一个字符串,有一个操作:把首字符放到末尾,形成新的串.求任意次操作后,字典序最小的串的首字母在原串中的位置.(这就是最小表示法?哈) 把原串翻倍,建立后缀自动机.然后在自动机上从起点往当前节点的较小的字母上跑len步即可.代码: #include<cstdio> #include<cstring> #include<iostream> #define MAXN 40050 #define

poj 1509 Glass Beads

题意:给你一个长度为n的字符串环,以位置i开始的顺时针长度为n的环构成的字符串有n个,问其中最小字典序的开始位置,有多种解时,输出起始位置最小的. 分析: 首先可以直接拼接两个长度为n的字符串,设原串为S[0],S[1]...S[n-1]则拼接后就是S'=S[0],S[1],...S[n-1],S[0],S[1],...S[n-1]. 那么问题中的n个长度为n的字符串中的任意一个,一定存在S'的某个后缀字符串的前缀与其相等. 我们现在要找最小字典序,则可以直接先求S'的后缀数组SA,然后: 1.

hdu4622(后缀自动机模板)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意: 先输入一个长度为 n 的字符串, 然后有 q 个形如 l, r 的询问, 对于每个询问输出区间 [l, r] 中有多少不同的子串 思路: 后缀自动机模板 代码: 1 // 后缀自动机要理解其含义,从起点到每个点的不同路径,就是不同的子串. 2 // 到每一个点,不同路径,其实就是以这个点为最后一个字符的后缀,长度是介于(p->fa->len,p->len]之间的,个数也就清楚

PKU 1509 Glass Beads (最小表示法)

题意:有一个环形字符串,让你找一个位置切一刀使得字符串字母序最小,输出这个位置. 思路:可以看成两个字符串比较,一个是从下标0开始(0~n-1),一个从下标1开始(1~n-1,0). 然后两个指针i=0,j=1.从s[i]和s[j]开始比较第k个字符是否相同,当k==len时,返回i,j中的最小值.当s[i+k]和s[j+k]不相同时,若s[i+k]>s[j+k]则可见从s[i+1]到s[i+k]都不会是最小字典序的起始位置,所以i=i+k+1.当s[i+k]<s[j+k]时同理.若移动后i=

广义后缀自动机模板

后缀自动机能解决很多单串的问题.但是一旦到了多串的情况.可能就会变得有些棘手 这个时候你可能会想能不能将多个串一起构建出和单串后缀自动机那样子拥有诸多优美性质的自动机呢? 答案当然是有的.那就是广义后缀自动机 对于广义后缀自动机.和普通的后缀自动机写法上有些许不同之处 大致就是在插入新串的时候.需要把当前状态指针 last 指回 root 还有一个问题.网上的人们都说广义后缀自动机在新插入节点的时候要判是否已经存在 这个就造成了代码的迥异 关于代码.借鉴了这个博客 ==> Click here

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

题目: 给定一个字符串a,又给定一系列b字符串,求字符串a的子串不在b中出现的个数. 题解: 先将所有的查询串放入后缀自动机(每次将sam.last=1)(算出所有子串个数) 然后将母串放入后缀自动机然后记录这个子串个数 两个值相减即可 1 #include <set> 2 #include <map> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <

POJ 1509 Glass Beads---最小表示法

题意: T组数据,每组数据给出一个字符串,求这个字符串的最小表示发(只要求输出起始位置坐标) SAM入门题(检测板子是否正确). 将字符串S加倍丢进SAM中,然后走字符串长度次,每次贪心的沿最小的边走,然后答案就是:sam.e[po].len-len+1 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib&