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

对于 $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. 关于JFace的自定义对话框(Dialog类)

    仅仅是使用MessageDialog,InputDialog等JFace中现成的对话框类是无法满足实际项目开发需要的. 很多时候都需要自己定制对话框,自定义对话框只要在Dialog类的基础上作扩展就行 ...

  2. js数组求和

    array1.reduce(callbackfn[, initialValue]) callback : 函数执行在数组中每个值 initialValue : 对象作为第一个参数回调的第一次调用使用 ...

  3. mysql计算连续天数,mysql连续登录天数,连续天数统计

    mysql计算连续天数,mysql连续登录天数,连续天数统计 >>>>>>>>>>>>>>>>>& ...

  4. wordpress 提取头像的src

    获取用户头像,可以通过 $avatar_html = get_avatar( $email ); 获取到头像的html /** * Retrieve the avatar url for a user ...

  5. 浅谈SqlCommand

    初学asp.net 的菜鸟应该都会像我一样想尝试一下前后台的交互吧!特别是与数据库的交互.下面就来说一下自己的个人经历. SqlCommand 首先需要引入system.Date.SqlClient命 ...

  6. dirname(__FILE__) 的使用总结

    dirname(__FILE__) php中定义了一个很有用的常数,即 __file__ 这个内定常数是当前php程序的就是完整路径(路径+文件名). 即使这个文件被其他文件引用(include或re ...

  7. RabbitMQ 原文译04--路由

    在前一篇文章中我们构建了一个简单的日志系统,我们可以向多个接受者广播消息. 在这篇文章我,我们将要添加一些功能使得针对部分消息的接受成为可能,例如我们只对错误的消息进行磁盘记录,同时又可以把所有的消息 ...

  8. Apache 流媒体 拖动模块编译

    Windows使用apxs独立编译 Apache 模块 http://blog.sina.com.cn/s/blog_43b83d340100mdhl.html 安装 apxs 1.解压apxs.zi ...

  9. 字符串 前篇 ---- sizeof()操作符和strlen()库函数

    本文不是研究sizeof(), strlen() 的深奥定义和原理,我们不会在理论上太过钻牛角尖.希望读这篇文章的你,也不要太过抠概念(不要拘泥于语法).我们只做 实用意义 的介绍和讨论. 在介绍字符 ...

  10. iOS开发——屏幕尺寸适配

    对于屏幕尺寸适配,目前先指竖屏的方式适合方式1和2. 1.控件尺寸写死的方式,偶尔会用到屏幕的宽度和高度. UILabel *holdLabel = [[UILabel alloc]initWithF ...