标签:
Time Limit: 3000MS | Memory Limit: 10000K | |
Total Submissions: 2827 | Accepted: 1634 |
Description
Input
Output
Sample Input
4 helloworld amandamanda dontcallmebfu aaabaaa
Sample Output
10 11 6 5
大意:
给出多组数据,每组数据包含一个字符串,求出这个字符串的同构串中字典序最小的串,输出开始的位置.
分析:
后缀自动机的简单应用:
后缀自动机的性质就是从初始态走到任意一个节点都是当前字符串的字串.
证明:
后缀自动机能够接受当前的串的所有的后缀.
在某个时刻,查询的字符串就是整个字符串某个前缀的后缀.所以能够接受.
根据这个性质
把两个串接在一起,然后就直接在上面依着最小字典序的边贪心地跑,最后跑到一个终止节点.
如何计算起始位置呢?
这个串能够接受的最长的串长,也就是这个点的step.就是从字符串开始到这个点在字符串中的长度.(它曾经是一个结束节点last)
所以我们只要用它减掉原串长就ok了.
代码比较简单.
1 #include<cstdlib> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 using namespace std; 7 const int maxn = (int)1e5, sigma = 26; 8 struct Sam{ 9 int ch[maxn][sigma],par[maxn]; 10 int stp[maxn]; 11 int sz,last; 12 void init(){ 13 memset(ch,0,sizeof(ch)); 14 memset(par,0,sizeof(par)); 15 memset(stp,0,sizeof(stp)); 16 sz = last = 1; 17 } 18 void extend(int c){ 19 stp[++sz] = stp[last] + 1; 20 int p = last, np = sz; 21 for(; !ch[p][c]; p = par[p]) ch[p][c] = np; 22 if(p == 0) par[np] = 1; 23 else{ 24 int q = ch[p][c]; 25 if(stp[q] != stp[p] + 1){ 26 stp[++sz] = stp[p] + 1; 27 int nq = sz; 28 memcpy(ch[nq],ch[q],sizeof(ch[q])); 29 par[nq] = par[q]; 30 par[q] = par[np] = nq; 31 for(; ch[p][c] == q; p = par[p]) ch[p][c] = nq; 32 } 33 else par[np] = q; 34 } 35 last = np; 36 } 37 void build(string &s){ 38 int i; 39 init(); 40 for(i = 0; i < s.size(); ++i) extend(s[i] - ‘a‘); 41 } 42 void vis(int len){ 43 int x = 1,i,j; 44 for(i = 0; i < len; ++i) 45 for(j = 0; j < sigma; ++j) 46 if(ch[x][j]){ x = ch[x][j]; break; } 47 cout << stp[x] - len + 1 << endl; 48 } 49 }sam; 50 string s; 51 int main() 52 { 53 freopen("bead.in","r",stdin); 54 freopen("bead.out","w",stdout); 55 ios::sync_with_stdio(false); 56 int n,i; 57 cin >> n; 58 for(i = 1; i <= n; ++i){ 59 cin >> s; 60 s = s + s; 61 sam.build(s); 62 sam.vis(s.size() / 2); 63 } 64 return 0; 65 }
标签:
原文地址:http://www.cnblogs.com/Mr-ren/p/4209532.html