SPOJ NSUBSTR

NSUBSTR - Substrings

 

题意:

  给一个字符串S,求长度为x的所有子串中,这些子串其中一个串的出现次数最多,求这个值。x=1,2,3....n

 

分析:

  后缀自动机。

  right集合表示当前状态在出现在其他的位置。len为当前状态的最大的串。parent树中,父节点的right包含子节点,所有对子节点拓扑即可求出所有点的right。

  当前节点的最大串为len,那么这个串的出现次数就是|right|,right集合的大小,更新出每个长度的最多出现次数。当然小于len的串也可以出现这些次,所有最后用ans[i+1]更新ans[i]即可。

 

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 250010;
11 
12 struct Suffix_Automaton{
13     int Index, Last, fa[N<<1], trans[N<<1][26], len[N<<1];
14     int du[N<<1],q[N<<1],ans[N],Right[N<<1],L,R;
15     char s[N];
16     
17     void extend(int c) {
18         int P = Last, NP = ++Index;
19         len[NP] = len[P] + 1;
20         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
21         if (!P) fa[NP] = 1;
22         else {
23             int Q = trans[P][c];
24             if (len[P] + 1 == len[Q]) fa[NP] = Q;
25             else {
26                 int NQ = ++Index;
27                 fa[NQ] = fa[Q];
28                 len[NQ] = len[P] + 1;
29                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
30                 fa[Q] = NQ;
31                 fa[NP] = NQ;
32                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
33             }
34         }
35         Last = NP;
36     }
37     void solve() {
38         scanf("%s",s);
39         
40         Index = 0;
41         Last = ++Index;
42         int n = strlen(s);
43         for (int i=0; i<n; ++i) extend(s[i] - 'a');
44         
45         for (int i=0,p=1; i<n; ++i) p=trans[p][s[i]-'a'], Right[p]++; // 将S(1~i)的点设为1,因为这个点的R的状态只能是1,并且parent树上没有子节点,注意字符串从0开始 
46         L = 1,R = 0;
47         for (int i=1; i<=Index; ++i) du[fa[i]] ++;
48         for (int i=1; i<=Index; ++i) 
49             if (!du[i]) q[++R] = i;
50         while (L <= R) { // 拓扑 
51             int u = q[L++];
52             Right[fa[u]] += Right[u];
53             du[fa[u]] --;
54             if (!du[fa[u]]) q[++R] = fa[u];
55         }
56         for (int i=1; i<=Index; ++i) 
57             ans[len[i]] = max(ans[len[i]], Right[i]);
58         for (int i=n-1; i>=0; --i) 
59             ans[i] = max(ans[i], ans[i+1]);
60         for (int i=1; i<=n; ++i) printf("%d\n",ans[i]);
61     }
62 }sam;
63 
64 int main() {
65     sam.solve();
66     return 0;
67 }

 

posted @ 2018-07-19 11:11  MJT12044  阅读(219)  评论(0编辑  收藏  举报