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]$$
然后再进行一次深搜就可以了。。
#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] 弦论 解题报告的更多相关文章
- BZOJ 3997 [TJOI 2015 组合数学] 解题报告
这个题我脑洞了一个结论: 首先,我们定义满足以下条件的路径为“从右上到左下的路径”: 对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有: $x_1\neq x_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 ...
- BZOJ 3990 [SDOI 2015] 排序 解题报告
这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...
- 解题:TJOI 2015 弦论
题面 好像是个经典问题,然而我没做过 建SAM,然后经过每个节点的子串数目就可以求了,多个相同子串算一个的话就把所有siz都搞成$1$,否则就是$right$集合的大小,然后就是常见的递推 求第$k$ ...
- 洛谷 P3975 [TJOI2015]弦论 解题报告
P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...
- bzoj 1565 [NOI2009]植物大战僵尸 解题报告
1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2161 Solved: 1000[Submit][Stat ...
- BZOJ 4029 [HEOI 4029] 定价 解题报告
这个题好像也是贪心的感觉.. 我们枚举 $1,5,10,50,100,\dots$ ,找出在 $[l, r]$ 内能整除它们的最小的数. 然后找到其中在荒谬值最小的情况下数值最小的那个数, 就做完了. ...
- BZOJ 3955 Surely You Congest 解题报告
首先,我们可以求出源为 $1$ 号点的最短路图以及各个点到 $1$ 号点的最短路. 然后我们考虑那些距离不同的点,是一定不会发生拥堵现象的. 然后我们就只需要考虑那些距离相同的点,就相当于做一个最大流 ...
- BZOJ 3929 Circle of digits 解题报告
首先,我们可以得到最高位的位数为:\(\lfloor\frac{n+k-1}{n}\rfloor\),记作 \(E\). 然后给这 \(n\) 个长为 \(E\) 的数字排序,后缀数组 \(O((n+ ...
随机推荐
- Windows服务定时运行,判断当前时间是否在配置时间段内
/// <summary> /// 判断程序是否在设置运行时间内 /// </summary> /// <param name="startTime" ...
- 一些实用的js高级技巧
技巧一之setTimeout. 应用案例:比如你想一个函数循环执行10次,怎么办?以前通常是先setInterval,然后clearInterval,技巧一就是克服这个问题 (function () ...
- Android richtext
在项目开发过程中经常会遇到很多需要显示不同样式的,不同风格的文本信息:对此可以使用多个TextView来分别设置自已想要的样式以满足需求,但是使用多个TextView的方式不太好:使用多个TextVi ...
- JavaScript高级程序设计(七):JavaScript中的in关键字
in 使用点一: 在js中,for--in用于遍历一个对象的属性,把对象的属性名和属性值都提出来. var obj = { "key1":"value1", & ...
- ###《Machine Learning in Action》 - KNN
初学Python:理解机器学习. 算法是需要实现的,纸上得来终觉浅. // @author: gr // @date: 2015-01-16 // @email: forgerui@gmail.com ...
- Android系统简介(中):系统架构
Android的系统架构栈分为4层,从上往下分别是Applications.Application framework.Libraries & Android Runtime.Linux ...
- ASP.NET 常识
1..NET是什么? .Net全称.NET Framework是一个开发和运行环境, 该战略是微软的一项全新创意, 它将使得"互联网行业进入一 ...
- MySQL5.7 linux二进制安装
200 ? "200px" : this.width)!important;} --> 介绍 MySQL5.7出来也有大半年了,业内也一直在宣传5.7有多么的N,官网的也是宣 ...
- C#基础(五)——类中私有构造函数作用
如果类成员有private修饰符,就不允许在类范围以外访问这个类成员.对类构造函数应用private修饰符时,则禁止外部类创建该类的实例.尽管看上去有些不好理解(既然不能实例化,那么这个类还有什么用处 ...
- js调用asp.net 后台属性值
后台代码: public string title = "js调用后台属性值"; public void getContent() { return title; } 前台代码: ...