【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 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以 ...
随机推荐
- Codeforces Round #340 (Div. 2) E 莫队+前缀异或和
E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...
- C++类成员空间分配和虚函数表
最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...
- golang channel状态表
如果我们查看该表,可以察觉到在操作中可能产生问题的地方.这里有三个可能导致阻塞的操作,以及三 个可能导致程序恐慌的操作. 乍看之下,通道的使用上限制很多,但在检查了这个限制产生的动机并熟悉 了通道的使 ...
- Intellj IDEA使用技巧记录
▲.Intellj IDEA光标变成了insert光标状态 且不能编辑操作: https://blog.csdn.net/aosica321/article/details/52787418 ▲.在i ...
- 如何在WIndows电脑上安装 SVN Server 实现代码版本控制
One 下载-安装 SVN SVNServer 先去官网下载服务器版本的svn server,下载地址 :https://www.visualsvn.com/server/download/ 选 ...
- JS常用面试题
一.闭包: 1.函数嵌套函数.内部函数可以引用外部函数的参数和变量. 参数和变量不会被垃圾回收机制所收回 function aaa(a){ var b = 5; function bbb(){ ...
- [数据库中间件]将用户添加到DB2组授权
1.将用户oracle添加到db2的用户组中,命令如下: usermod -a -G db2iam #将用户添加到组中并不改变当前所属组 注:以下与主题无关,只是列举一些关于用户的命令 id user ...
- vue-router.esm.js?fe87:16 [vue-router] Route with name 'page' does not exist
本文地址:http://www.cnblogs.com/veinyin/p/7910525.html 我的路由配置 { path: '/page', name: page, component: pa ...
- 在mac上安装ruby
1.先装RVM,一个多版本ruby环境的管理和切换工具 curl -sSL https://get.rvm.io | bash -s stable 会自动装上最新版.更新RVM版本:$ rvm get ...
- PHP对象5: define / const /static
define定义全局常量: define('PATH', '/data/home/www'); const也是定义常量, 一般用于类中, 饰成员属性,不可以修饰方法,如下: class Test{ c ...