【SAM】POJ1509-Glass Beads
【题目大意】
求一个循环数列的最小表示法。
【思路】
把原创复制一遍放在后面,建立SAM,从s按字典序开始跑长度L即可。
板子来源(作者见连接内):🌺
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=10007*2; 7 char str[MAXN]; 8 int len; 9 10 struct SAM 11 { 12 int step[MAXN],next[MAXN][26],pre[MAXN]; 13 int tot,last; 14 15 inline int newNode(int cnt) 16 { 17 step[++tot]=cnt; 18 pre[tot]=0; 19 for (int i=0;i<26;i++) next[tot][i]=0; 20 return tot; 21 } 22 23 inline void extend(int x) 24 { 25 int p=last; 26 int np=newNode(step[last]+1); 27 while (p && !next[p][x]) next[p][x]=np,p=pre[p]; 28 if (!p) pre[np]=1; 29 else 30 { 31 int q=next[p][x]; 32 if (step[q]==step[p]+1) pre[np]=q; 33 else 34 { 35 int nq=newNode(step[p]+1); 36 for (int i=0;i<26;i++) next[nq][i]=next[q][i]; 37 pre[nq]=pre[q]; 38 pre[q]=pre[np]=nq; 39 while (p && next[p][x]==q) next[p][x]=nq,p=pre[p]; 40 } 41 } 42 last=np; 43 } 44 45 inline void add(int x) 46 { 47 extend(x); 48 } 49 50 inline void init() 51 { 52 tot=0; 53 last=newNode(0); 54 } 55 }suf; 56 57 void programinit() 58 { 59 scanf("%s",str); 60 len=strlen(str); 61 for (int i=0;i<len;i++) str[i+len]=str[i]; 62 suf.init(); 63 for (int i=0;i<len*2;i++) suf.add(str[i]-'a'); 64 } 65 66 void solve() 67 { 68 int j=1; 69 for (int i=0;i<len;i++) 70 for (int k=0;k<26;k++) 71 if (suf.next[j][k]) 72 { 73 j=suf.next[j][k]; 74 break; 75 } 76 printf("%d\n",suf.step[j]-len+1); 77 } 78 79 int main() 80 { 81 int T; 82 scanf("%d",&T); 83 while (T--) 84 { 85 programinit(); 86 solve(); 87 } 88 }