POJ-1509 Glass Beads
题意:求一个字符串的最小表示的开始下标。
分析:其实有一个O(N)的算法专门来解决这个问题,并且实现非常简单,不过后缀自动机同样能够解决这个问题。首先把这个串重复两次,然后从前往后一一将字符加入到后缀自动机中,最后从根开始向下遍历串的长度层即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 using namespace std; 7 const int MAXN=10000+10; 8 char str[MAXN]; 9 struct SAM{ 10 struct State{ 11 int ch[26]; 12 int link,len; 13 void init(){ 14 link=-1; 15 len=0; 16 memset(ch,0xff,sizeof(ch)); 17 } 18 }st[MAXN<<1]; 19 int size,last; 20 void init(){ 21 size=last=0; 22 st[size++].init(); 23 } 24 int newst(){ 25 st[size].init(); 26 return size++; 27 } 28 void add(int c){ 29 int end=newst(); 30 int p=last; 31 st[end].len=st[last].len+1; 32 for(;p!=-1 && st[p].ch[c] == -1;p=st[p].link) 33 st[p].ch[c]=end; 34 if(p == -1) st[end].link=0; 35 else { 36 int nxt=st[p].ch[c]; 37 if(st[p].len+1 == st[nxt].len) st[end].link=nxt; 38 else { 39 int clone=newst(); 40 st[clone]=st[nxt]; 41 st[clone].len=st[p].len+1; 42 st[end].link=st[nxt].link=clone; 43 for(;p!=-1 && st[p].ch[c]==nxt;p=st[p].link) 44 st[p].ch[c]=clone; 45 } 46 } 47 last=end; 48 } 49 }sam; 50 51 int main(){ 52 int T; 53 scanf("%d",&T); 54 while(T--){ 55 sam.init(); 56 scanf("%s",str); 57 int len=strlen(str); 58 for(int i=0;i<len*2;i++){ 59 sam.add(str[i%len]-'a'); 60 } 61 int p=0; 62 for(int i=0;i<len;i++){ 63 for(int j=0;j<26;j++){ 64 if(sam.st[p].ch[j] != -1){ 65 p=sam.st[p].ch[j]; 66 break; 67 } 68 } 69 } 70 printf("%d\n",sam.st[p].len-len+1); 71 } 72 return(0); 73 }