【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 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以 ...
随机推荐
- UESTC--1267
原题链接:http://www.acm.uestc.edu.cn/problem.php?pid=1267 分析:此题麻烦之处在于要输出最小最长上升子序列,关键在于如何解决最小这个问题. 我的做法是从 ...
- Linux系统之路——python多版本共存问题(ps:自行切换python版本,pip安装遇到的一些问题)
经常遇到这样的情况: 系统自带的Python是2.6,自己需要Python 2.7中的某些特性: 系统自带的Python是2.x,自己需要Python 3.x: 此时需要在系统中安装多个Python, ...
- UVA - 1262 数学
UVA - 1262 题意: 有两个6*5 的大写字母组成的矩阵,需要找出满足条件的字典序第k小的密码:密码中每个字母在两个矩阵的对应的同一列中都出现过 代码: // 先处理出来每一列可以取的字母,例 ...
- 手脱PEtite v2.1
1.载入PEID PEtite v2.1 2.载入OD,先F8跟一下 0042C10F > B8 00C04200 mov eax,跑跑排行.0042C000 ; //程序入口点 0042C11 ...
- jeecms上传文件限制导致413-Request Entity Too Large
1:spring mvc 上传限制大小 配置是否允许在上传文件的大小 <bean id="multipartResolver" class="org.spring ...
- (转)JAVA 十六个常用工具类
一. org.apache.commons.io.IOUtils closeQuietly 关闭一个IO流.socket.或者selector且不抛出异常.通常放在finally块 toString ...
- 往android主项目中添加辅助项目
一个较大的工程往往需要多个项目组成,便于更好的并行开发和管理,但最后还是要合到一起来发布.那如何往主项目里添加其他辅助项目呢? 通常的做法是将辅助项目打包成jar包,像库一样导入到主项目,但是如果我们 ...
- OpenCV---色彩空间(一)
颜色空间:用三种或者更多特征来指定颜色的方法,被称为颜色空间或者颜色模型 1.RGB(OpenCV中为BGR): 一幅图像由三个独立的图像平面或者通道构成:红.蓝.绿(以及可选项:透明度alpha通道 ...
- Java设计模式の迭代器模式
迭代器模式定义 迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 迭代器模式的角色构成 (1)迭代器角色(Iterator):定义遍历元素所需 ...
- CF821 E. Okabe and El Psy Kongroo 矩阵快速幂
LINK 题意:给出$n$条平行于x轴的线段,终点$k$坐标$(k <= 10^{18})$,现在可以在线段之间进行移动,但不能超出两条线段的y坐标所夹范围,问到达终点有几种方案. 思路:刚开始 ...