【LOJ】#2012. 「SCOI2016」背单词
题解
我们发现第一种操作肯定不可取,每个节点里它最近的点是它最长出现过的后缀,发现这就是AC自动机的fail节点,根据fail的关系这会是一棵树,而一个单词的前一个序号最大的后缀必定是它的父亲
然后我们考虑怎么获得最小值,x是肯定要加上的,我们让每次减掉的y最小
一个错误的想法:按照儿子个数分类,建一个set,每次拿儿子最小的= =
emmm这个,如果你有一条10^3的链和1个点5个儿子比较一下,会发现这是错的
我们不拿这个点会造成多少贡献来看,我们初始设置每个点要减去的值都是0,我们挑选了一个点,这个点所在子树除外的其他子树,要减去的值都会+1
这样的话,我们只要每次找出所有能选的点,用set维护一下,然后每次拿一个子树大小最小的点作为这个位置上填的单词就可以了
【AC自动机写挂了一次,以前都是26个指针填满,但是这回是链前,必须遍历过每个fail直到找到对应的字符边】
代码
#include <bits/stdc++.h>
//#define ivorysi
#define MAXN 510005
typedef long long int64;
typedef unsigned int u32;
using namespace std;
struct node{
int to,next,val;
}edge[MAXN * 2];
int fail[MAXN],rt = 1,head[MAXN],sumE,nodecnt = 1,ed[MAXN],siz[MAXN];
int n,len,id[MAXN],fa[MAXN];
char s[MAXN];
bool vis[MAXN];
vector<int> g[MAXN],son[MAXN];
int que[MAXN],tot;
struct data {
int id;
friend bool operator < (const data &a,const data &b) {
return siz[a.id] < siz[b.id] || (siz[a.id] == siz[b.id] && a.id < b.id);
}
friend bool operator == (const data &a,const data &b) {
return a.id == b.id;
}
};
set<data> S;
void add(int u,int v,int c) {
edge[++sumE].to = v;
edge[sumE].next = head[u];
edge[sumE].val = c;
head[u] = sumE;
}
int find_edge(int u,int c) {
for(int i = head[u] ; i ; i = edge[i].next) {
if(edge[i].val == c) return edge[i].to;
}
return 0;
}
queue<int> Q;
void build_ACAM() {
Q.push(1);
fail[1] = 1;
while(!Q.empty()) {
int u = Q.front();Q.pop();
for(int i = head[u] ; i ; i = edge[i].next) {
int v = edge[i].to;
if(u == 1) fail[v] = u;
else {
int t = fail[u];
int x = 0;
while(1) {
x = find_edge(t,edge[i].val);
if(x > 0) break;
if(t == 1) break;
t = fail[t];
}
fail[v] = x > 0 ? x : 1;
}
Q.push(v);
g[fail[v]].push_back(v);
}
}
}
void ins(int id) {
int p = rt;
for(int i = 1 ; i <= len ; ++i) {
int v = find_edge(p,s[i] - 'a');
if(v == 0) {
v = ++nodecnt;
add(p,v,s[i] - 'a');
}
p = v;
}
ed[p] = id;
}
void Init() {
scanf("%d",&n);
for(int i = 1 ; i <= n ; ++i) {
scanf("%s",s + 1);
len = strlen(s + 1);
ins(i);
}
build_ACAM();
}
void dfs(int u,int last_f) {
if(ed[u]) {que[++tot] = ed[u];siz[ed[u]] = 1;}
if(last_f && ed[u]) {
son[last_f].push_back(ed[u]);
fa[ed[u]] = last_f;
}
for(auto k : g[u]) {
if(ed[u]) dfs(k,ed[u]);
else dfs(k,last_f);
}
}
void Solve() {
ed[1] = n + 1;
dfs(1,0);
int64 ans = 1LL * n * (n + 1) / 2;
for(int i = tot ; i >= 1 ; --i) {
siz[fa[que[i]]] += siz[que[i]];
}
S.insert((data){ed[1]});
for(int i = 0 ; i <= n ; ++i) {
auto it = S.begin();
int x = (*it).id;
S.erase(it);
id[x] = i;
ans -= id[fa[x]];
for(auto k : son[x]) {
S.insert((data){k});
}
}
printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}
【LOJ】#2012. 「SCOI2016」背单词的更多相关文章
- loj#2012. 「SCOI2016」背单词
题目链接 loj#2012. 「SCOI2016」背单词 题解 题面描述有点不清楚. 考虑贪心 type1的花费一定不会是优的,不考虑, 所以先把后缀填进去,对于反串建trie树, 先填父亲再填儿子, ...
- AC日记——「SCOI2016」背单词 LiBreOJ 2012
#2012. 「SCOI2016」背单词 思路: Orz: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...
- 「SCOI2016」背单词 解题报告
「SCOI2016」背单词 出题人sb 题意有毒 大概是告诉你,你给一堆n个单词安排顺序 如果当前位置为x 当前单词的后缀没在这堆单词出现过,代价x 这里的后缀是原意,但不算自己,举个例子比如abc的 ...
- 「SCOI2016」背单词
「SCOI2016」背单词 Lweb 面对如山的英语单词,陷入了深深的沉思,「我怎么样才能快点学完,然后去玩三国杀呢?」.这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,然后 ...
- loj2012 「SCOI2016」背单词
-- #include <algorithm> #include <iostream> #include <cstring> #include <cstdio ...
- loj#2013. 「SCOI2016」幸运数字 点分治/线性基
题目链接 loj#2013. 「SCOI2016」幸运数字 题解 和树上路径有管...点分治吧 把询问挂到点上 求出重心后,求出重心到每个点路径上的数的线性基 对于重心为lca的合并寻味,否则标记下传 ...
- loj#2015. 「SCOI2016」妖怪 凸函数/三分
题目链接 loj#2015. 「SCOI2016」妖怪 题解 对于每一项展开 的到\(atk+\frac{dnf}{b}a + dnf + \frac{atk}{a} b\) 令$T = \frac{ ...
- loj#2016. 「SCOI2016」美味
题目链接 loj#2016. 「SCOI2016」美味 题解 对于不带x的怎么做....可持久化trie树 对于带x,和trie树一样贪心 对于答案的二进制位,从高往低位贪心, 二进制可以表示所有的数 ...
- loj #2013. 「SCOI2016」幸运数字
#2013. 「SCOI2016」幸运数字 题目描述 A 国共有 n nn 座城市,这些城市由 n−1 n - 1n−1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以 ...
随机推荐
- NYOJ--69
数的长度 原题链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=69 分析:先看看求n!的朴素算法,用大整数乘法来实现. #include< ...
- HDU1536:S-Nim(sg函数)
S-Nim Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- Linux常用网络工具:路由扫描之mtr
除了上一篇<Linux常用网络工具:路由扫描之traceroute>介绍的traceroute之外,一般Linux还内置了另一个常用的路由扫描工具mtr. mtr在某些方面比tracero ...
- 微信小程序,页面分享
onShareAppMessage: function () { return { title: '微信小程序联盟', desc: '最具人气的小程序开发联盟!', path: '/page/user ...
- [Java多线程]-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
- OpenCV---人脸检测
一:相关依赖文件下载 https://github.com/opencv/opencv 二:实现步骤(图片检测) (一)读取图片 image= cv.imread("./d.png&qu ...
- css之display:inline-block布局--转
css之使用display:inline-block来布局 css之display:inline-block布局 1.解释一下display的几个常用的属性值,inline , block, in ...
- Shiro实战教程(一)
Shiro完整架构图 Shiro认证过程 Shiro授权的内部处理机制 Shiro 支持三种方式的授权 1.编程式:通过写if/else 授权代码块完成: Subject subject = Secu ...
- kali2.0安装虚拟机工具
kali2.0无法安装虚拟机工具,显示VMware Tools无法用于该虚拟机,或者安装之后无法进行复制.粘贴等操作. 解决办法: step1: 更换源 root@starnight:~# vim / ...
- 固定bottom,页面其它可滑动实现方案
利用flex布局, <html> <body> <div class='container'> <div class='content'></di ...