题目链接

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. 201521123018 《Java程序设计》第13周学习总结

    1. 本章学习总结 2. 书面作业 一.1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 返回时间 ...

  2. 201521123085 《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  3. [LeetCode]Count and Say 计数和发言

    Count and Say 计数和发言 思路:首先要理解题意,可以发现后者是在前者的基础之上进行的操作,所以我们拿之前的结果作为现在函数的参数循环n-1次即可,接下来就是统计字符串中相应字符的个数,需 ...

  4. shell脚本之算术运算和逻辑运算

    目录 算术运算 赋值运算 逻辑运算 短路运算和异或 条件测试 数值测试 字符串测试 文件及其属性测试 存在性测试 存在性及类别测试 文件权限测试 文件特殊权限测试 文件大小测试 文件是否打开 双目测试 ...

  5. 使用IntelliJ IDEA查看类的继承关系图形

    最近正好也没什么可忙的,就回过头来鼓捣过去的知识点,到Servlet部分时,以前学习的时候硬是把从上到下的继承关系和接口实现记得乱七八糟. 这次利用了IDEA的diagram,结果一目了然,也是好用到 ...

  6. jmeter测试HTTP请求

    HTTP超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.(详情参考看一下百科) HTTP发送请求有GE ...

  7. SQL三类语句

    1. DDL (Data Definition Language, 数据定义语言) CREATE: 创建数据库和表等对象 DROP: 删除数据库和表等对象 ALTER: 修改数据库和表等对象的结构 2 ...

  8. 用postal.js在AngularJS中实现订阅发布消息

    点击查看AngularJS系列目录 用postal.js在AngularJS中实现event bus 用postal.js在AngularJS中实现event bus 理想状态下,在一个Angular ...

  9. 使用千位分隔符(逗号)表示web网页中的大数字

    做手机端页面我们常常遇到数字,而在Safari浏览器下这些数字会默认显示电话号码,于是我们就用到了补坑的方法加入<meta>标签: <meta name="format-d ...

  10. C++ Primer Plus 6 第二章

    // myfirst.cpp--displays a message #include <iostream> // a PREPROCESSOR directive int main() ...