BZOJ 3998 [TJOI 2015] 弦论 解题报告
这是一道后缀自动机经典题目。
对于 $t=0$ 的情况:每个节点都代表一个子串,所以我们给每个节点的 $Size$ 都记为 $1$,
对于 $t=1$ 的情况:我们只给 $last$ 节点的 $Size$ 记为 $1$,因为新建的虚拟节点并不能给子串数目带来贡献。然后再建出 $pre$ 指针树,每个串的出现次数就是其在 $pre$ 指针树上的子树的 $Size$ 和。
然后我们进行拓扑图 Dp, $Dp[u]$ 表示从 $u$ 号节点往后走会有多少种子串,转移的话:
$$Dp[u] = \sum_{i=0}^{26}Dp[Son[u][i]] + Size[u]$$
然后再进行一次深搜就可以了。。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 #define N 500000 + 5 9 10 int n, t, k, cnt, tot, last; 11 int Head[N << 1], q[N << 1]; 12 LL Size[N << 1]; 13 bool Vis[N << 1]; 14 char s[N]; 15 16 struct Edge 17 { 18 int next, node; 19 }E[N << 1]; 20 21 struct Suffix_Automation 22 { 23 int pre, step, son[26]; 24 }h[N << 1]; 25 26 inline void addedge(int u, int v) 27 { 28 E[++ cnt].next = Head[u]; 29 Head[u] = cnt; 30 E[cnt].node = v; 31 } 32 33 inline void addchar(char ch) 34 { 35 int np = ++ tot, p = last, j = ch - 'a'; 36 h[np].step = h[p].step + 1; 37 Size[np] = 1; 38 for (; p && !h[p].son[j]; p = h[p].pre) 39 h[p].son[j] = np; 40 if (!p && !h[p].son[j]) 41 h[p].son[j] = np, h[np].pre = p; 42 else 43 { 44 int q = h[p].son[j]; 45 if (h[q].step == h[p].step + 1) 46 h[np].pre = q; 47 else 48 { 49 int nq = ++ tot; 50 h[nq].step = h[p].step + 1; 51 Size[nq] = t ? 0 : 1; 52 for (int i = 0; i < 26; i ++) 53 h[nq].son[i] = h[q].son[i]; 54 h[nq].pre = h[q].pre; 55 h[q].pre = h[np].pre = nq; 56 for (; h[p].son[j] == q; p = h[p].pre) 57 h[p].son[j] = nq; 58 } 59 } 60 last = np; 61 } 62 63 inline void BFS(int S) 64 { 65 int l = 0, r = 0; 66 q[0] = S; 67 while (l <= r) 68 { 69 int z = q[l ++]; 70 for (int i = Head[z]; i; i = E[i].next) 71 { 72 int d = E[i].node; 73 q[++ r] = d; 74 } 75 } 76 for (; r; r --) 77 { 78 if (h[q[r]].pre) 79 Size[h[q[r]].pre] += Size[q[r]]; 80 } 81 } 82 83 inline void dfs(int z) 84 { 85 if (Vis[z]) return ; 86 Vis[z] = 1; 87 for (int i = 0; i < 26; i ++) 88 if (h[z].son[i]) 89 { 90 dfs(h[z].son[i]); 91 Size[z] += Size[h[z].son[i]]; 92 } 93 } 94 95 inline void Solve(int p, int k) 96 { 97 LL sum = 0; 98 for (int i = 0; i < 26; i ++) 99 if (h[p].son[i]) 100 sum += Size[h[p].son[i]]; 101 if (Size[p] - sum >= k) return ; 102 k -= Size[p] - sum, sum = 0; 103 for (int i = 0; i < 26; i ++) 104 if (h[p].son[i]) 105 { 106 if (sum < k && k <= sum + Size[h[p].son[i]]) 107 { 108 putchar('a' + i); 109 Solve(h[p].son[i], k - sum); 110 break ; 111 } 112 else sum += Size[h[p].son[i]]; 113 } 114 } 115 116 int main() 117 { 118 #ifndef ONLINE_JUDGE 119 freopen("3998.in", "r", stdin); 120 freopen("3998.out", "w", stdout); 121 #endif 122 123 scanf("%s", s); 124 scanf("%d%d", &t, &k); 125 n = strlen(s); 126 for (int i = 0; i < n; i ++) 127 addchar(s[i]); 128 if (t) 129 { 130 for (int i = 1; i <= tot; i ++) 131 addedge(h[i].pre, i); 132 BFS(0); 133 } 134 dfs(0); 135 if (Size[0] < k) puts("-1"); 136 else Solve(0, k); 137 putchar('\n'); 138 139 #ifndef ONLINE_JUDGE 140 fclose(stdin); 141 fclose(stdout); 142 #endif 143 return 0; 144 }