这是一道后缀自动机经典题目。

对于 $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]$$

然后再进行一次深搜就可以了。。

 #include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define N 500000 + 5 int n, t, k, cnt, tot, last;
int Head[N << ], q[N << ];
LL Size[N << ];
bool Vis[N << ];
char s[N]; struct Edge
{
int next, node;
}E[N << ]; struct Suffix_Automation
{
int pre, step, son[];
}h[N << ]; inline void addedge(int u, int v)
{
E[++ cnt].next = Head[u];
Head[u] = cnt;
E[cnt].node = v;
} inline void addchar(char ch)
{
int np = ++ tot, p = last, j = ch - 'a';
h[np].step = h[p].step + ;
Size[np] = ;
for (; p && !h[p].son[j]; p = h[p].pre)
h[p].son[j] = np;
if (!p && !h[p].son[j])
h[p].son[j] = np, h[np].pre = p;
else
{
int q = h[p].son[j];
if (h[q].step == h[p].step + )
h[np].pre = q;
else
{
int nq = ++ tot;
h[nq].step = h[p].step + ;
Size[nq] = t ? : ;
for (int i = ; i < ; i ++)
h[nq].son[i] = h[q].son[i];
h[nq].pre = h[q].pre;
h[q].pre = h[np].pre = nq;
for (; h[p].son[j] == q; p = h[p].pre)
h[p].son[j] = nq;
}
}
last = np;
} inline void BFS(int S)
{
int l = , r = ;
q[] = S;
while (l <= r)
{
int z = q[l ++];
for (int i = Head[z]; i; i = E[i].next)
{
int d = E[i].node;
q[++ r] = d;
}
}
for (; r; r --)
{
if (h[q[r]].pre)
Size[h[q[r]].pre] += Size[q[r]];
}
} inline void dfs(int z)
{
if (Vis[z]) return ;
Vis[z] = ;
for (int i = ; i < ; i ++)
if (h[z].son[i])
{
dfs(h[z].son[i]);
Size[z] += Size[h[z].son[i]];
}
} inline void Solve(int p, int k)
{
LL sum = ;
for (int i = ; i < ; i ++)
if (h[p].son[i])
sum += Size[h[p].son[i]];
if (Size[p] - sum >= k) return ;
k -= Size[p] - sum, sum = ;
for (int i = ; i < ; i ++)
if (h[p].son[i])
{
if (sum < k && k <= sum + Size[h[p].son[i]])
{
putchar('a' + i);
Solve(h[p].son[i], k - sum);
break ;
}
else sum += Size[h[p].son[i]];
}
} int main()
{
#ifndef ONLINE_JUDGE
freopen("3998.in", "r", stdin);
freopen("3998.out", "w", stdout);
#endif scanf("%s", s);
scanf("%d%d", &t, &k);
n = strlen(s);
for (int i = ; i < n; i ++)
addchar(s[i]);
if (t)
{
for (int i = ; i <= tot; i ++)
addedge(h[i].pre, i);
BFS();
}
dfs();
if (Size[] < k) puts("-1");
else Solve(, k);
putchar('\n'); #ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return ;
}

3998_Gromah

BZOJ 3998 [TJOI 2015] 弦论 解题报告的更多相关文章

  1. BZOJ 3997 [TJOI 2015 组合数学] 解题报告

    这个题我脑洞了一个结论: 首先,我们定义满足以下条件的路径为“从右上到左下的路径”: 对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有: $x_1\neq x_2 ...

  2. BZOJ 3996 [TJOI 2015] 线性代数 解题报告

    首先,我们可以得到: $$D = \sum_{i=1}^{n}\sum_{j=1}^{n}a_i\times a_j\times b_{i,j} - \sum_{i=1}^{n}a_i\times c ...

  3. BZOJ 3990 [SDOI 2015] 排序 解题报告

    这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...

  4. 解题:TJOI 2015 弦论

    题面 好像是个经典问题,然而我没做过 建SAM,然后经过每个节点的子串数目就可以求了,多个相同子串算一个的话就把所有siz都搞成$1$,否则就是$right$集合的大小,然后就是常见的递推 求第$k$ ...

  5. 洛谷 P3975 [TJOI2015]弦论 解题报告

    P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...

  6. bzoj 1565 [NOI2009]植物大战僵尸 解题报告

    1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2161  Solved: 1000[Submit][Stat ...

  7. BZOJ 4029 [HEOI 4029] 定价 解题报告

    这个题好像也是贪心的感觉.. 我们枚举 $1,5,10,50,100,\dots$ ,找出在 $[l, r]$ 内能整除它们的最小的数. 然后找到其中在荒谬值最小的情况下数值最小的那个数, 就做完了. ...

  8. BZOJ 3955 Surely You Congest 解题报告

    首先,我们可以求出源为 $1$ 号点的最短路图以及各个点到 $1$ 号点的最短路. 然后我们考虑那些距离不同的点,是一定不会发生拥堵现象的. 然后我们就只需要考虑那些距离相同的点,就相当于做一个最大流 ...

  9. BZOJ 3929 Circle of digits 解题报告

    首先,我们可以得到最高位的位数为:\(\lfloor\frac{n+k-1}{n}\rfloor\),记作 \(E\). 然后给这 \(n\) 个长为 \(E\) 的数字排序,后缀数组 \(O((n+ ...

随机推荐

  1. 关于oozie

    什么是Oozie? Oozie是一个工作流引擎服务器,用于运行Hadoop Map/Reduce和Pig 任务工作流.同时Oozie还是一个Java Web程序,运行在Java Servlet容器中, ...

  2. 关于Git远程版本库

    Git作为分布式版本库控制系统,每个人都是本地版本库的主人,可以在本地的版本库中随心所欲的创建分支和里程碑. 当需要多人协作时,问题就出现了: 1.如何避免因为用户把所有的本地分支都推送到了共享版本库 ...

  3. MATLAB-ginput函数问题

    functions:Graphical input from mouse or cursor ginput提供了一个十字光标使我们能更精确的选择我们所需要的位置,并返回坐标值.函数调用形式为: [x, ...

  4. 图像处理函数详解——im2bw

    im2bw是基于转换为二值图像的算法,用的是otsu's method. matlab中DIP工具箱函数im2bw使用阈值(threshold)变换法把灰度图像(grayscale image)转换成 ...

  5. C#前端頁面判斷控件

    var chbClass = document.getElementById("<%=DDL_CheckboxUserClass1.ClientID %>" + &qu ...

  6. 关于async和await的一些误区实例详解

    转载自 http://www.jb51.net/article/53399.htm 这篇文章主要介绍了关于async和await的一些误区实例详解,有助于更加深入的理解C#程序设计,需要的朋友可以参考 ...

  7. MongoDB 的分组操作 In C#

    C#对mongodb的分组查询操作,主要通过脚本或Aggregate方法来实现,以下通过一些实例作解析: 参考资料:http://www.tuicool.com/articles/2iqUZj   h ...

  8. iOS开发——企业证书(免审核 299$)

    (最近准备考试……空闲截图整理成博客)

  9. Java实战之04JavaWeb-08文件上传与下载

    一.文件上传 1.文件上传的实质是什么 文件的拷贝,文件从客户端拷贝服务器端 2.文件上传的工作 (1)客户端怎样将本地文件输出去? 1)文件上传的表单项 <input type=”file”& ...

  10. 建造者模式(Builder Pattern)

    建造者模式:使用多个简单对象一步步构建成一个复杂的对象. 有时候,我们会创建一个“复杂”的对象,这个对象的由很多子对象构成,由于需求的变化,这个对象的各个部分经常面临剧烈的变化. 继续工厂模式的披萨店 ...