HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)
Now George is working on a word list containing N words.
He has so poor a memory that it is too hard for him to remember all
of the words on the list. But he does find a way to help him to
remember. He finds that if a sequence of words has a property that for
all pairs of neighboring words, the previous one is a substring of the
next one, then the sequence of words is easy to remember.
So he decides to eliminate some words from the word list first to
make the list easier for him. Meantime, he doesn't want to miss the
important words. He gives each word an importance, which is represented
by an integer ranging from -1000 to 1000, then he wants to know which
words to eliminate to maximize the sum of the importance of remaining
words. Negative importance just means that George thought it useless and
is a waste of time to recite the word.
Note that although he can eliminate any number of words from the
word list, he can never change the order between words. In another word,
the order of words appeared on the word list is consistent with the
order in the input. In addition, a word may have different meanings, so
it can appear on the list more than once, and it may have different
importance in each occurrence.
Each test case contains several lines.
The first line contains an integer N(1 <= N <= 2 * 10
4), indicating the number of words.
Then N lines follows, each contains a string S
i and an integer W
i, representing the word and its importance. S
i contains only lowercase letters.
You can assume that the total length of all words will not exceeded 3 * 10
5.OutputFor each test case in the input, print one line: "Case #X:
Y", where X is the test case number (starting with 1) and Y is the
largest importance of the remaining sequence of words.Sample Input
1
5
a 1
ab 2
abb 3
baba 5
abbab 8
Sample Output
Case #1: 14
题解:
给定n个字符串,要求按顺序取一些字符串,满足后一个字符串是前一个字符串的子串,要求使得取出的权值和最大。
题目类似一般的DP问题,项最长上升子序列,只不过把上升的要求改成了是前一个的子串,权重也发生了改变 。
判断子串关系,我们用AC 自动机。
我们把AC自动机的fail指针拿出来建立一棵树,然后在求这棵树的dfs序,对于每个点,我所能得到的最大权值一定是该点到root的所有权值。然后我们对每个点的in[x],和out[x]之间的dfs序去更新。
每次取最大值即可
参考代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=3e5+;
int cnt,root,n,kase,w[+],pos[+];
int INDEX,in[maxn],out[maxn];
char s[maxn];
int fail[maxn];
int S[maxn*],tag[maxn*],MAX,L,R;
int st[maxn],tot;
struct edge {
int v,nxt;
}v[maxn*];
inline void addedge(int x,int y)
{
v[tot]=(edge){y,st[x]};
st[x]=tot++;
}
struct node {
int nxt[],cnt;
}T[maxn];
inline int newnode()
{
cnt++; memset(T[cnt].nxt,,sizeof(T[cnt].nxt));
T[cnt].cnt=; fail[cnt]=;
return cnt;
}
inline void insert(char *s)
{
int now=root; int i=;
while(s[i])
{
if(!T[now].nxt[s[i]-'a'])T[now].nxt[s[i]-'a']=newnode();
now=T[now].nxt[s[i]-'a']; i++;
}
T[now].cnt++;
}
queue<int>Q;
inline void build()
{
Q.push(root);
while(!Q.empty())
{
int k=Q.front(); Q.pop();
if(k!=root)addedge(fail[k],k);
for(int i=;i<;++i)
{
if(!T[k].nxt[i]){T[k].nxt[i]=T[fail[k]].nxt[i];continue;}
if(k!=root)
fail[T[k].nxt[i]]=T[fail[k]].nxt[i];
Q.push(T[k].nxt[i]);
}
}
}
inline void DFS(int u,int fa)
{
in[u]=++INDEX;
for(int i=st[u];~i;i=v[i].nxt)
if(v[i].v!=fa) DFS(v[i].v,u);
out[u]=INDEX;
}
inline void update(int k)
{
S[k]=max(S[k<<],S[k<<|]);
}
inline void down(int k)
{
if(!tag[k])return ;
tag[k<<]=max(tag[k<<],tag[k]);
tag[k<<|]=max(tag[k<<|],tag[k]);
S[k<<]=max(S[k<<],tag[k]);
S[k<<|]=max(S[k<<|],tag[k]); tag[k]=;
}
inline int ask(int l,int r,int k)
{
if(L<=l&&r<=R)return S[k];
int mid=(l+r)>>; down(k);
int res=;
if(L<=mid)res=max(res,ask(l,mid,k<<));
if(R>mid)res=max(res,ask(mid+,r,k<<|)); return res;
}
inline void add(int l,int r,int k)
{
if(L<=l&&r<=R)
{
S[k]=max(S[k],MAX); tag[k]=max(tag[k],MAX);
return ;
}
int mid=(l+r)>>; down(k);
if(L<=mid)add(l,mid,k<<);
if(R>mid)add(mid+,r,k<<|);
update(k);
}
int main()
{
int t; scanf("%d",&t);
while(t--)
{
scanf("%d",&n); cnt=-;
root=newnode(); tot=;
memset(st,-,sizeof(st));
pos[]=;
for(int i=;i<=n;++i)
{
scanf("%s%d",s+pos[i-],w+i);
pos[i]=pos[i-]+strlen(s+pos[i-]);
insert(s+pos[i-]);
}
build();
INDEX=;
DFS(root,-);
int ans=;
memset(S,,sizeof(S));
memset(tag,,sizeof(tag));
for(int i=;i<=n;++i)
{
MAX=; int p=root;
for(int j=pos[i-];j<pos[i];++j)
{
p=T[p].nxt[s[j]-'a']; L=in[p];R=in[p];
int res=ask(,INDEX,);
MAX=max(res,MAX);
}
MAX=MAX+w[i];
ans=max(ans,MAX);
L=in[p];R=out[p];
add(,INDEX,);
}
printf("Case #%d: %d\n",++kase,ans);
}
return ;
}
HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)的更多相关文章
- hdu 4117 -- GRE Words (AC自动机+线段树)
题目链接 problem Recently George is preparing for the Graduate Record Examinations (GRE for short). Obvi ...
- HDU 5069 Harry And Biological Teacher(AC自动机+线段树)
题意 给定 \(n\) 个字符串,\(m\) 个询问,每次询问 \(a\) 字符串的后缀和 \(b\) 字符串的前缀最多能匹配多长. \(1\leq n,m \leq 10^5\) 思路 多串匹配,考 ...
- 背单词(AC自动机+线段树+dp+dfs序)
G. 背单词 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使 ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
- 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解
这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...
- 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树
题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...
- hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)
E. e-Government time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...
随机推荐
- Spring Cloud gateway 七 Sentinel 注解方式使用
Sentinel 注解支持 @SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项. @SentinelResource 注解包含以下属性: value:资 ...
- SqlServer2005 查询 第四讲 in
今天我们来说sql中的命令参数in in --in用于查询某个字段的指定的值的记录信息 注意一下:--对或(or)取反是并且(and),对并且(and)取反是或(or 数据库中不等于表示有两种:!= ...
- 插入排序的代码实现(C语言)
void insert_sort(int arr[], int len) { for (int i = 1; i < len; ++i) { if (arr[i] < arr[i - 1] ...
- Linux注意事项
一.学习 Linux 的注意事项 1. Linux 严格区分大小写 Linux 是严格区分大小写的,这一点和 Windows 不一样,所以操作时要注意区分大小写的不同,包括文件名和目录名.命令.命令选 ...
- ThreadLocal原理分析与代码验证
ThreadLocal提供了线程安全的数据存储和访问方式,利用不带key的get和set方法,居然能做到线程之间隔离,非常神奇. 比如 ThreadLocal<String> thread ...
- 使用CGLIB实现动态代理
参考:https://blog.csdn.net/yhl_jxy/article/details/80633194#comments CGLIB动态代理 定义:CGLIB(code genaratio ...
- Jib插件构建镜像push到阿里云镜像仓库
一.前言 Jib:Google开源的Java容器化工具 可作为插件快速集成到项目中,构建镜像,实现 Java 应用容器化 下面贴出一张从网上看到的Jib描述~ 二.利用Jib插件构建镜像push到阿里 ...
- web前端开发面试题(Vue.js)
1.active-class是哪个组件的属性?嵌套路由怎么定义? 答:vue-router模块的router-link组件. 2.怎么定义vue-router的动态路由?怎么获取传过来的动态参数? ...
- 2019-9-11:渗透测试,Kill远控软件,初接触
初步使用Kill远控软件,使win7靶机被远控 该文章仅供学习,利用方法来自网络文章,仅供参考 1,打开运行Kill,选择系统设置,设置监听端口,通讯密码,点击保存设置 2,点击服务生成,上线参 ...
- 【2018寒假集训 Day2】【动态规划】抢金块
抢金块 输入文件:gold.in 输出文件:gold.out 问题描述: 地面上有一些格子,每个格子上面都有金块,但不同格子上的金块有不同的价值,你一次可以跳S至T步 .如果S=2,T=4.你就可以跳 ...