题目链接

problem

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. 


Input

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

Output

For 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

思路:AC自动机+线段树。这题直观的想法是以每个字符串为尾串,求在当前串之前选取字符串并以当前串为结束得到的最大值,即dp[i]=max(dp[j])+w[i],s[j]是s[i]的子串且j<i;
我们可以反向建立fail树,那么对于串s[i]的最后一位指向的孩子,均是包含s[i]的串,所以以s[i]的最后一位为根节点的子树中的孩子节点表示的串均包含s[i],那么我们对串s[1]~s[n]逐一进行计算时,可以把结
果用线段树更新到子树中,然后对于每个串计算时,只需要考虑s[i]的每一位能得到的最大值(线段树单点查询),最后取最大值加上w[i],即为s[i]的最大值,然后更新到子树中。 代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
const int N=2e4+;
const int M=3e5+;
char s[M];
int w[N],pos[N]; struct Node
{
int son[];
}node[M];
int fail[M];
int root,tot; struct Edge
{
int to;
int next;
}edge[M];
int head[M],cnt; int in[M],out[M],tp; ///树节点序号化; int tx[M*],tf[M*],L,R,tmp; ///线段树; inline int newnode()
{
tot++;
memset(node[tot].son,,sizeof(node[tot].son));
fail[tot]=;
return tot;
} inline void addEdge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
} inline void insert(char s[])
{
int now=root;
for(int i=;s[i];i++)
{
if(!node[now].son[s[i]-'a'])
node[now].son[s[i]-'a']=newnode();
now=node[now].son[s[i]-'a'];
}
}
inline void build()
{
queue<int>Q;
Q.push(root);
while(!Q.empty())
{
int now=Q.front(); Q.pop();
if(now!=root) addEdge(fail[now],now);
for(int i=;i<;i++)
{
if(node[now].son[i])
{
if(now!=root)
fail[node[now].son[i]]=node[fail[now]].son[i];
Q.push(node[now].son[i]);
}
else node[now].son[i]=node[fail[now]].son[i]; }
}
}
inline void dfs(int now)
{
in[now]=++tp;
for(int i=head[now];i;i=edge[i].next)
{
dfs(edge[i].to);
}
out[now]=tp;
}
inline void pushdown(int i)
{
if(!tf[i]) return ;
int pre=tf[i];
tf[i<<]=max(tf[i<<],pre);
tf[i<<|]=max(tf[i<<|],pre);
tx[i<<]=max(tx[i<<],pre);
tx[i<<|]=max(tx[i<<|],pre);
tf[i]=;
}
inline int query(int l,int r,int i)
{
if(l==r) return tx[i];
int mid=(l+r)>>;
pushdown(i);
if(L<=mid) return query(l,mid,i<<);
else return query(mid+,r,i<<|);
}
inline void update(int l,int r,int i)
{
if(L<=l&&r<=R)
{
tf[i]=max(tf[i],tmp);
tx[i]=max(tx[i],tmp);
return ;
}
int mid=(l+r)>>;
pushdown(i);
if(L<=mid) update(l,mid,i<<);
if(R>mid) update(mid+,r,i<<|);
tx[i]=max(tx[i<<],tx[i<<|]);
} void init()
{
tot=-;
cnt=;
tp=;
root=newnode();
memset(head,,sizeof(head));
memset(fail,,sizeof(fail));
memset(tx,,sizeof(tx));
memset(tf,,sizeof(tf));
}
int main()
{
int T,Case=; scanf("%d",&T);
while(T--)
{
init();
int n; scanf("%d",&n);
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();
dfs(root);
int ans=;
for(int i=;i<=n;++i)
{
tmp=;
int now=root;
for(int j=pos[i-];j<pos[i];++j)
{
now=node[now].son[s[j]-'a'];
L=in[now]; R=in[now];
int res=query(,tp,);
tmp=max(tmp,res);
}
tmp+=w[i];
ans=max(ans,tmp);
L=in[now];
R=out[now];
update(,tp,);
}
printf("Case #%d: %d\n",Case++,ans);
}
return ;
}

hdu 4117 -- GRE Words (AC自动机+线段树)的更多相关文章

  1. hdu 4117 GRE Words AC自动机DP

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

  2. HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)

    Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...

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

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

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

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

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

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

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

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

  7. hdu 2896 病毒侵袭 ac自动机

    /* hdu 2896 病毒侵袭 ac自动机 从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉 last[]数组主要是记录具有相同后缀模式串的末尾节点编号 .本 ...

  8. 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)

    [BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...

  9. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

随机推荐

  1. 201521123118《java程序与设计》第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 1. finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中fi ...

  2. java课程设计-算术运算测试

    1. 团队名称.团队成员介绍 团队名称:cococo 团队成员 组长:网络1514叶城龙 201521123109 组员:网络1514余腾鑫 201521123108 2. 项目git地址 http: ...

  3. ThreadLocal原理及使用示例

    简介:本文已一个简要的代码示例介绍ThreadLocal类的基本使用方式,在此基础上结合图片阐述它的内部工作原理. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblog ...

  4. [06] Session实现机制以及和Cookie的区别

    1.为什么有Session和Cookie 根据早期的HTTP协议,每次request-reponse时,都要重新建立TCP连接.TCP连接每次都重新建立,所以服务器无法知道上次请求和本次请求是否来自于 ...

  5. webservice07#契约优先#webservice实现简单的动态web项目

    1, 用户管理 User{username,password,nickname} 属性. 2,契约优先[ 先用schema做标准来写wsdl.再生成服务器端的接口,再编写接口的类] 在src下创建目录 ...

  6. JSP-页面跳转大全

    转自:http://blog.sina.com.cn/s/blog_8c38b8b701013zzz.html (1). forward()方法 使用到javax.servlet.RequestDis ...

  7. Myeclipse黑色主题配置

    Myeclipse自己打造黑色主题: 一.UI Theme(设置黑色主题模式): 如果是自己下载在的.jar主题,则首先将该jar包放在Myeclipse安装目录下的\dropins\plugins\ ...

  8. MySql 中文乱码解决办法

    mysql存入的中文数据乱码,可能有这两个原因 原因一 : 数据源配置和mysql字符集编码不符,或数据源配置没有设置字符集 解决方案:在数据源配置添加字符集 useUnicode=true& ...

  9. AngularJS的$rootScope和$scope联系和区别

    scope是html和单个controller之间的桥梁,数据绑定就靠他了. rootscope是各个controller中scope的桥梁.用rootscope定义的值,可以在各个controlle ...

  10. gRPC官方快速上手学习笔记(c#版)

    上手前准备工作 支持操作系统:windows.OS X.Linux.实例采用.net..net core sdk. The .NET Core SDK command line tools. The ...