1. 程式人生 > >[SPOJ-NSUBSTR]Substrings

[SPOJ-NSUBSTR]Substrings

ngs root pan void 每一個 忽略 [] 後綴自動機 clu

題目大意:
  給你一個字符串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 }

[SPOJ-NSUBSTR]Substrings