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+ ...
随机推荐
- hadoop的相关资料链接
hadoop的资料整理博客 http://www.itpub.net/thread-1588509-1-1.html
- 关于properties文件在项目中的使用
这个是当时在学习JDBC的时候老师给讲的.web项目中把一些常用的用户名和密码都填写到一个对应的配置文件中,这样每次修改密码或者用户名的时候就可以直接修改这个配置文件了,不用动源码. 老师讲了两种读取 ...
- update目标在查询返回结果集中的解决方案
示例: students为学生信息表 Score为成绩表 两个表通过学生号关联 要求:将总成绩小于100的学生名称改为‘天才’ sql如下: error提示:update目标不能在查询返回结果集中 ...
- 【转】ArrayList的toArray,也就是list.toArray[new String[list.size()]];,即List转为数组
[转]ArrayList的toArray ArrayList提供了一个将List转为数组的一个非常方便的方法toArray.toArray有两个重载的方法: 1.list.toArray(); 2.l ...
- ArrayUtils用法
/* 1. ArrayUtils.isEmpty(strs) : 判断数组是否为空 , 不为空返回false,为空true */ ArrayUtils.isEmpty(new String[] ...
- java中的拷贝文件FileChannel
以前用Java拷贝文件,只知道写byte数组循环拷贝,今天知道了可以用FileChannel进行拷贝,上代码: 下边是传统的byte数组拷贝方法 </pre><pre name=&q ...
- ios llvm and clang build tools
1. 使用 libclan g或 clang 插件 包括( libclang 和 Clangkit) 备注: Clangkit,它是基于 clang 提供的功能,用 Objective-C 进行封装 ...
- makefile文件制作入门
一.首先,看一下最简单的C文件 //hello.c文件 #include <stdio.h> void main() { printf("hello world\n") ...
- Android系统简介(中):系统架构
Android的系统架构栈分为4层,从上往下分别是Applications.Application framework.Libraries & Android Runtime.Linux ...
- Java教程——int与Integer的区别
首先说一下int和Integer的区别: int 是基本数据类型,Integer是int的包装类.注意:后者的类型是"类".例如使用泛型,List<Integer> n ...