【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 }

 

转载于:https://www.cnblogs.com/iiyiyi/p/5733455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值