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 }