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