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('
');
138     
139     #ifndef ONLINE_JUDGE
140         fclose(stdin);
141         fclose(stdout);
142     #endif
143     return 0;
144 }
3998_Gromah
原文地址:https://www.cnblogs.com/gromah/p/4452558.html