【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 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以 ...
随机推荐
- The 14th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple - F 贪心+二分
Heap Partition Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge A sequence S = { ...
- sloop公共程序之总体描述
1:功能需求 开发一个公共库文件sloop.c,实现三个常用功能以供其它模块调用.三个功能如下: 功能一:实现一般的信号监听,调用模块只需传入要监听的信号和相应的回调函数就可以在信号到时调用回调函数处 ...
- clinical significance临床显著性
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...
- phpstrom+xdebug+chrome+postman调试工具搭建
php是解释性语言,大部分调试的时候使用var_dump+exit就可以搞定了,但是在大项目或遇到了负载的问题的时候你就需要断点调试.变量打印.性能分析了,php也有非常程序的解决方案,我们现在就动手 ...
- Ubuntu 14.04.3 window10双系统情遇到'Disconnected: You are now offline'问题
笔电是win10系统,单独开除50G做了一个Ubuntu系统,安装的是14.04.03版本,安装成功后,发现wifi连接不上,选择wifi并输入密码后提示:“Disconnected: You are ...
- 在vue中使用animate.css
animate.css是一款前端动画库,相似的有velocity-animate 用法: 首先 npm install animate.css --save 然后在vue文件的script中引入: i ...
- Goolge-Guava Concurrent中的Service
最近在学习了下Google的Guava包,发现这真是一个好东西啊..由于平时也会写一些基于多线程的东西,所以特意了解了下这个Service框架.这里Guava包里的Service接口用于封装一个服务对 ...
- 【CodeForces】913 C. Party Lemonade
[题目]C. Party Lemonade [题意]给定n个物品,第i个物品重量为2^(i-1)价值为ci,每个物品可以无限取,求取总重量>=L的最小代价.1<=30<=n,1< ...
- array_unshift() 函数
出处:http://www.w3school.com.cn/php/func_array_unshift.asp
- Windows 7 64 位操作系统安装 Ubuntu 17.10
一.准备工作 1. DiskGenius:分区工具,为 Linux 建立单独的分区.(Linux 公社下载源) 2. UUI:Universal USB Installer,通用 U 盘安装器,用来制 ...