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

对于 $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. 排序并获取index的顺序

    //排序并获取index的顺序:4,7,2,9-->9,7,4,2-->4,2,1,3 Array.prototype.getIndex=function(){ var orderLeng ...

  2. linux 远程工具

    SecureCRT SecureCRT官网地址:http://www.vandyke.com/products/securecrt/ Xmanager官方网址:http://www.netsarang ...

  3. PHP持续保有长连接,利用flush持续更新浏览器UI,下载进度条实现

    如何用PHP+JS实现上传进度条,大部分的人可能都实现过,但是下载呢?如何呢?原理也是差不多的,就是分次读写,每次读多少字节,但是这样的不好就是长连接,一般实现下载进度条常用的两种解决方案是:一种是需 ...

  4. JAXB - Annotations, Annotation for Classes: XmlType

    This annotation adds information that would be available from a schema type, but isn't implied by a ...

  5. ASP判断文件地址是否有效

    <% Response.Write("<head><style><!--span{ font-size: 9pt }--></style> ...

  6. Spring AOP (Spring 3.x 企业应用开发实战读书笔记第六章)

    从面相对象编程到面相切面编程,是一种代码组织方式的进化. 每一代的代码组织方式,其实是为了解决当时面对的问题.比如写编译器和写操作系统的时候的年代当然要pop,比如写界面的时候当然要oop,因为界面这 ...

  7. SQL Server2008数据库如何改名

    未使用的数据库改名比较方便,找到你要更改的数据库,右键选择[重命名]. 2 然后将你想要更改的名字写好,然后点击一下旁边的空白栏. 3 然后你就发现数据库的名称已经改好了. END 使用中的数据库   ...

  8. 【JAVA】浅谈java内部类

    一.什么是内部类? 到底什么是内部类呢?通俗的讲,就是在类内部定义的类,包括定义在一个类的方法外面.方法里面或者代码块中. 二.为什么要使用内部类? 为什么我们要不走寻常路,把一个类定义在另一个类的内 ...

  9. ###再探Makefile

    使用makefile.以前刚开始接触Makefile的时候,写过一个最简单的Makefile.点击查看Evernote原文. #@author: gr #@date: 2014-07-20 #@ema ...

  10. ###《More Effective C++》- 操作符

    More Effective C++ #@author: gr #@date: 2015-05-21 #@email: forgerui@gmail.com 五.对定制的"类型转换函数&qu ...