【题解】GREWords(AC自动机)
【题解】GREWords(AC自动机)
题目大意:
给定一个由字符串构成的序列,不同位置的字符串有自己权值。现在让你选出一个子序列,使得在这个子序列中,前面的串是后面的串的子串。请你求满足条件的子序列的权值的最大值。一个子序列权值是所有元素权值的和。
考虑一个朴素的DP做法,设\(dp(i)\)表示选择了字符串\(i\)的最大权值子序列,转移直接枚举前面的字符串,通过\(kmp\)判断是否为子串,然后转移,复杂度\(O(n^3)\)
考虑优化一下上面的做法,众所周知,ac自动机\(fail\)树上任意节点到根一条链是一段后缀。那么,一个字符串的所有子串就是它在ac自动机上的所有节点的所有到根链。(子串=自己某段前缀的后缀)
要优化上面那个\(dp\),就是要求我们维护一个数据结构,使得可以根据一个字符串快速查询已有的他所有的子串的权值的最大值。考虑这样一种做法,把\(fail\)树单独拿出来,现在假设我有个\(dp\)值更新就只会对他的子树有影响,考虑到子树的一段连续的\(dfs\)序列,所以直接线段树维护一个区间取\(max\)单点求\(max\)即可。
可以直接先把fail建出来再依次更新\(dp\),使得fail树的形态确定。
总复杂度\(O(n\log n)\)
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=3e5+5;
const int inf=1e9+5;
int to[maxn],w[maxn];
char c[maxn];
string sav[maxn];
namespace Graph{}
namespace ACautomaton{}
namespace SegmentTree{int n,que(const int&,const int&,const int&,const int&);}
namespace Graph{
vector<int> e[maxn];
int dfn[maxn],End[maxn],timer;
inline void add(const int&fr,const int&to){
e[fr].push_back(to);
e[to].push_back(fr);
}
void dfs(const int&now,const int&last){
dfn[now]=++timer;
for(auto t:e[now])
if(t!=last)
dfs(t,now);
End[now]=timer;
}
inline void init(){for(int t=0;t<maxn;++t) e[t].clear(); timer=0;}
}
namespace ACautomaton{
using Graph::add;
struct E{
int son[26],fail;
E(){memset(son,0,sizeof son); fail=0;}
inline int& operator [](int x){return son[x];}
inline int& operator [](char x){return son[x-'a'];}
}ac[maxn];
int cnt;
inline void add(const char*data,const int&n,const int&id){
int now=0;
for(int t=1;t<=n;++t){
if(!ac[now][data[t]]) ac[now][data[t]]=++cnt;
now=ac[now][data[t]];
}
to[id]=now;
}
queue<int> q;
inline void gen(){
queue<int>().swap(q);
for(char c='a';c<='z';++c)
if(ac[0][c])
q.push(ac[0][c]),ac[ac[0][c]].fail=0;
while(q.size()){
int now=q.front(); q.pop();
for(char c='a';c<='z';++c){
if(ac[now][c]) ac[ac[now][c]].fail=ac[ac[now].fail][c],q.push(ac[now][c]);
else ac[now][c]=ac[ac[now].fail][c];
}
}
for(int t=1;t<=cnt;++t) add(t,ac[t].fail);
}
inline void init(){memset(ac,0,sizeof ac); memset(to,0,sizeof to); memset(w,0,sizeof w); cnt=0;}
inline int getans(const string&f){
int now=0,ret=0;
for(const auto&t:f)
ret=max(ret,SegmentTree::que(Graph::dfn[now=ac[now][t]],1,SegmentTree::n,1));
return ret;
}
}
namespace SegmentTree{
#define pp(pos) seg[pos].val=max(seg[pos<<1].val,seg[pos<<1|1].val)
#define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
struct E{
int val,tag;
E(){val=tag=0;}
E(const int&a,const int&b){val=a; tag=b;}
}seg[maxn<<2];
inline void pd(const int&pos){
if(seg[pos].tag==0) return;
seg[pos<<1].val=max(seg[pos<<1].val,seg[pos].tag);
seg[pos<<1|1].val=max(seg[pos<<1|1].val,seg[pos].tag);
seg[pos<<1].tag=max(seg[pos<<1].tag,seg[pos].tag);
seg[pos<<1|1].tag=max(seg[pos<<1|1].tag,seg[pos].tag);
seg[pos].tag=0;
}
void build(const int&l,const int&r,const int&pos){
seg[pos].val=seg[pos].tag=0;
if(l==r) return;
build(lef); build(rgt);
}
void upd(const int&L,const int&R,const int&k,const int&l,const int&r,const int&pos){
if(L>r||R<l) return;
if(L<=l&&r<=R) {seg[pos].val=max(seg[pos].val,k); seg[pos].tag=max(seg[pos].tag,k); return;}
pd(pos);
upd(L,R,k,lef); upd(L,R,k,rgt);
pp(pos);
}
int que(const int&k,const int&l,const int&r,const int&pos){
if(k<l||k>r) return 0;
if(l==r) return seg[pos].val;
pd(pos);
int ret=max(que(k,lef),que(k,rgt));
pp(pos);
return ret;
}
inline void init(const int&a){n=a;build(1,n,1);}
#undef lef
#undef rgt
#undef mid
}
int main(){
int T=qr(),F=0;
while(T--){
ACautomaton::init();
Graph::init();
int n=qr();
for(int t=1;t<=n;++t){
scanf("%s",c+1);
sav[t]=c+1;
ACautomaton::add(c,strlen(c+1),t);
w[t]=qr();
}
ACautomaton::gen();
Graph::dfs(0,0);
SegmentTree::init(Graph::timer);
int ans=0;
for(int t=1;t<=n;++t){
int k=w[t]+ACautomaton::getans(sav[t]);
SegmentTree::upd(Graph::dfn[to[t]],Graph::End[to[t]],k,1,SegmentTree::n,1);
ans=max(k,ans);
}
printf("Case #%d: %d\n",++F,ans);
}
return 0;
}
【题解】GREWords(AC自动机)的更多相关文章
- CF 1400F x-prime Substrings 题解【AC自动机+DP】
CF 1400F.x-prime Substrings 题意: 给定一个由\('1'\)到\('9'\)组成的字符串\(s\)和一个数\(x\),定义一个串为\(x-prime\)串,当且仅当这个串上 ...
- 【题解】AC自动机题解合集
最近貌似大家都在搞字符串?很长一段时间都没有写博客了……还是补一补坑吧. 感觉AC自动机真的非常优美了,通过在trie树上建立fail指针可以轻松解决多模匹配的问题.实际上在AC自动机上的匹配可以看做 ...
- bzoj3940 censoring 题解(AC自动机)
题目描述 Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they h ...
- 【JSOI2007】文本生成器 题解(AC自动机+动态规划)
题目链接 题目大意:给定$n$个子串,要求构造一个长度为$m$的母串使得至少有一个子串是其子串.问方案数. ------------------------ 我们可以对要求进行转化:求出不合法的方案数 ...
- 【HDU2896】病毒侵袭 AC自动机
[HDU2896]病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年 ...
- 【HDU2222】Keywords Search AC自动机
[HDU2222]Keywords Search Problem Description In the modern time, Search engine came into the life of ...
- HDU2296——Ring(AC自动机+DP)
题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值.求字符串的最大价值.每个单词的价值就是单价*出现次数.单词可以重叠.如果不止一个答案,选择字典序最小 ...
- BZOJ 1212 [HNOI2004]L语言 【AC自动机 + 背包】
题目链接[http://www.lydsy.com/JudgeOnline/problem.php?id=1212] 题意:给你一些单词,然后给出一个没有标点的文本串S,都是小写字符.现在让你求用给出 ...
- bzoj 3172: [Tjoi2013]单词 AC自动机
3172: [Tjoi2013]单词 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
随机推荐
- Laravel Class config does not exist in
修改了Laravel里面的.env文件之后报这个错误,找半天,找到罪魁祸首了,错误信息: Fatal error: Uncaught ReflectionException: Class config ...
- Oracle中的Union、Union All、Intersect、Minus[转]
众所周知的几个结果集集合操作命令,今天详细地测试了一下,发现一些问题,记录备考. 假设我们有一个表Student,包括以下字段与数据: drop table student; create table ...
- H3C TCP与UDP的对比
- tensorflow入门——3解决问题——4让我们开始吧
深度学习适合解决海量数据和复杂问题 在机器学习中,语音识别,图像识别,语意识别用的是不同的技术,从事相关工作的人合作几乎不可能. 深度学习改变了这一切. 80年代计算机很慢,数据集很小,因此深度学习没 ...
- php-max_execution_time
有时候我们需要跑一个脚本,比如执行几十万个请求.如果你使用浏览器,请求服务器.这时就会出现执行中断,因为超时了.我们可以通过下面的方式: 修改php.ini配置文件 max_execution_tim ...
- 使用colab平台进行训练
https://www.zhongxiaoping.cn/2018/12/01/%E4%BD%BF%E7%94%A8colab%E5%B9%B3%E5%8F%B0%E8%BF%9B%E8%A1%8C% ...
- pip、conda 换国内源,大大提高下载速度
https://www.jianshu.com/p/b2d53904dd37 源就是下载地址了,换到国内的源下载速度真的快了近10倍,这里都用了清华的源 pip 只要新建一个配置文件,写上路径就行了 ...
- element-ui css 文件加载 失败(https://unpkg.com/element-ui/lib/theme-chalk/index.css,加载失败)
在main.js文件引入 import Vue from 'vue'; import Element from 'element-ui'; import 'element-ui/lib/theme ...
- 【转载】Windows平台下利用APM来做负载均衡方案 - 负载均衡(下)
概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...
- BiLSTM-CRF学习笔记(原理和理解) 维特比
BiLSTM-CRF 被提出用于NER或者词性标注,效果比单纯的CRF或者lstm或者bilstm效果都要好. 根据pytorch官方指南(https://pytorch.org/tutorials/ ...