Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the most important thing is reciting the words.
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.


InputThe first line contains an integer T(1 <= T <= 50), indicating the number of test cases.

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序)的更多相关文章

  1. hdu 4117 -- GRE Words (AC自动机+线段树)

    题目链接 problem Recently George is preparing for the Graduate Record Examinations (GRE for short). Obvi ...

  2. HDU 5069 Harry And Biological Teacher(AC自动机+线段树)

    题意 给定 \(n\) 个字符串,\(m\) 个询问,每次询问 \(a\) 字符串的后缀和 \(b\) 字符串的前缀最多能匹配多长. \(1\leq n,m \leq 10^5\) 思路 多串匹配,考 ...

  3. 背单词(AC自动机+线段树+dp+dfs序)

    G. 背单词 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较   题目描述 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使 ...

  4. hdu 4117 GRE Words AC自动机DP

    题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...

  5. 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解

        这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...

  6. 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树

    题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...

  7. hdu 4117 GRE Words (ac自动机 线段树 dp)

    参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...

  8. BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  9. 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 ...

随机推荐

  1. Python 基础 三 反射

    Python 基础 三 反射 今天我们先介绍一下反射这个概念,啥是反射?反射就是自己检测自己.在我们Python的面向对象中的反射是啥意思呢?就是通过字符串的形式操作对象相关的属性.python中的一 ...

  2. Git常用命令(基础)

    Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remote:远程仓库 一.新建代码库 # 在当前目录新建一个Git代码库 $ git in ...

  3. SpringBoot基本配置详解

    SpringBoot项目有一些基本的配置,比如启动图案(banner),比如默认配置文件application.properties,以及相关的默认配置项. 示例项目代码在:https://githu ...

  4. nyoj 975-关于521 (EOF)

    975-关于521 内存限制:64MB 时间限制:1000ms 特判: No 通过数:5 提交数:46 难度:2 题目描述: Acm队的流年对数学的研究不是很透彻,但是固执的他还是想一头扎进去. 浏览 ...

  5. 力扣(LeetCode)买卖股票的最佳时机 个人题解

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润. 注意你不能在买入股票前卖出股票. 示例 ...

  6. 根据本地ip获取地理位置,再根据地理位置,获取天气

    import json,requestsfrom urllib.request import urlopenfrom pyquery import PyQuery as pqfrom lxml imp ...

  7. 在idea中使用git

    在idea中使用git 1. 在idea中配置git ​ 安装好IntelliJ IDEA后,如果Git安装在默认路径下,那么idea会自动找到git的位置,如果更改了Git的安装位置则需要手动配置下 ...

  8. Java流程控制之(三)嵌套

    目录 嵌套循环 for循环嵌套 while循环嵌套 总结 之前谈到各种循环结构,有for循环啊,有while循环啊,可以完成不断重复的动作,相当方便.那么如果好多个循环结合再一次,又是如何实现效果的呢 ...

  9. C博客作业05--2019-指针

    0.展示PTA总分 1.本章学习总结 1.1 学习内容总结 1.2 本章学习体会 2.PTA实验作业 2.16 -7 输出月份英文名 2.1.1 伪代码 char* getmonth(int n) { ...

  10. Paramiko的SSH和SFTP使用

    目录 1. 概述 2. Paramiko的基本使用 2.1 SSHClient关键参数介绍 2.2 SSHClient常用示例 2.2.1 通过用户名和密码方式登陆: 2.2.2 通过用户名和密码方式 ...