[SPOJ-NSUBSTR]Substrings

题目大意:
  给你一个字符串s,求出不同长度出现次数最多的字串的最大出现次数。

思路:
  先对s构造后缀自动机,然后把s放进去匹配,每一个经过的结点表示一种长度的子串,用一个cnt记录能以每个状态表示的子串数量,然后按拓扑序DP。
  注意拓扑序并不等同于在SAM中插入的次序,因为用new_q替代q的操作会打乱顺序。(上一道题可能是因为数据弱被我卡过去了)
  然后我想到了DFS,以为从根结点开始得到的DFS序就是拓扑序,然而这样会忽略那些不是任何状态的后继状态,但是有link指针的状态(它们同样可以向上传递)。
  参考了网上的题解,发现常用的SAM拓扑排序方法很简单,直接按照每个状态到根结点的最长距离len排序即可。
  然而这样遍历每个状态肯定是连续的在一个数组中比较方便,然而我是用的指针(学陈立杰),于是又用数组模拟指针。
  然后还是WA。
  后来发现是指针改写成数组模拟的时候把pq打反了。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 const int LEN=250001;
 5 class SuffixAutomaton {
 6     private:
 7         static const int SIGMA_SIZE=26;
 8         int cnt[LEN],len,sz;
 9         struct State {
10             int link,go[SIGMA_SIZE];
11             int len,cnt;
12         };
13         State s[LEN<<1];
14         int newState(const int l) {
15             sz++; 
16             s[sz].link=NULL;
17             memset(s[sz].go,0,sizeof s[sz].go);
18             s[sz].len=l;
19             s[sz].cnt=0;
20             return sz;
21         }
22         int root,last;
23         int top[LEN<<1];
24         int idx(const char ch) {
25             return ch-'a'; 
26         }
27         void extend(const char ch) {
28             const int w=idx(ch);
29             int p=last;
30             int new_p=newState(s[p].len+1);
31             while(p!=NULL&&s[p].go[w]==NULL) {
32                 s[p].go[w]=new_p;
33                 p=s[p].link;
34             }
35             if(p==NULL) {
36                 s[new_p].link=root;
37             } else {
38                 int q=s[p].go[w];
39                 if(s[q].len==s[p].len+1) {
40                     s[new_p].link=q; 
41                 } else {
42                     int new_q=newState(s[p].len+1);
43                     memcpy(s[new_q].go,s[q].go,sizeof s[q].go);
44                     s[new_q].link=s[q].link;
45                     s[new_p].link=s[q].link=new_q;
46                     while(p!=NULL&&s[p].go[w]==q) {
47                         s[p].go[w]=new_q;
48                         p=s[p].link;
49                     }
50                 }
51             }
52             last=new_p;
53         }
54         void match(char ss[]) {
55             int p=root;
56             for(int i=0;i<len;i++) {
57                 p=s[p].go[idx(ss[i])];
58                 s[p].cnt++;
59             }
60         }
61         int f[LEN];
62     public:
63         void build(char s[]) {
64             len=strlen(s);
65             root=last=newState(0);
66             for(int i=0;i<len;i++) {
67                 extend(s[i]);
68             }
69         }
70         void query(char ss[]) {
71             match(ss);
72             for(int i=1;i<=sz;i++) cnt[s[i].len]++;
73             for(int i=len;i;i--) cnt[i-1]+=cnt[i];
74             for(int i=sz;i;i--) top[cnt[s[i].len]--]=i;
75             for(int i=1;i<=sz;i++) {
76                 if(s[top[i]].link!=NULL) {
77                     s[s[top[i]].link].cnt+=s[top[i]].cnt;
78                 }
79             }
80             for(int i=1;i<=sz;i++) {
81                 f[s[top[i]].len]=std::max(f[s[top[i]].len],s[top[i]].cnt);
82             }
83             for(int i=len;i;i--) {
84                 f[i]=std::max(f[i],f[i+1]);
85             }
86             for(int i=1;i<=len;i++) printf("%d\n",f[i]);
87         }
88 };
89 SuffixAutomaton sam;
90 char s[LEN];
91 int main() {
92     scanf("%s",s);
93     sam.build(s);
94     sam.query(s);
95     return 0;
96 }

 

posted @ 2017-09-14 07:03  skylee03  阅读(110)  评论(0编辑  收藏  举报