题目链接

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. MySQL的JOIN(五):JOIN优化实践之排序

    这篇博文讲述如何优化JOIN查询带有排序的情况.大致分为对连接属性排序和对非连接属性排序两种情况.插入测试数据. CREATE TABLE t1 ( id INT PRIMARY KEY AUTO_I ...

  2. 语句的分号、逗号和函数中var的使用

    1语句 分号 语句的结尾的分号不是必须的,但建议不要省略它,避免错误. 2逗号 1同时定义多个变量用逗号分开 2数组的最后一位,建议不要加上逗号,在有的浏览器中会导致,在逗号后添加一个undefine ...

  3. oracle客户端plsql设置字符集

    感谢一个新朋友的到来,我帮他的过程中有好些东西都不怎么想的起来了,所以从现在起我需要记录下每一点一滴, 因为我觉得写下来的东西才不会丢,而且欢迎以后的朋友到来. 使用plsql查数据的时候有时候中文会 ...

  4. JVM 运行时数据区总结 栈 堆 堆大小配置总结

    1. 程序计数器 线程私有 当前线程所执行的字节码的行号指示器 2. 虚拟机栈 线程私有 存:Java方法(局部变量表(基本数据类型).操作数栈.动态链栈.方法出口) StackOverflowErr ...

  5. 初识 JShell

    Java9 现在吵得热火朝天,赶紧顺势学习一波喽! JDK9 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk9-dow ...

  6. Sum It Up 广搜

    Sum It Up Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit St ...

  7. POJ1422Air Raid(二分图,最小不相交路径覆盖)

    Air Raid Consider a town where all the streets are one-way and each street leads from one intersecti ...

  8. 简单的CSS颜色查看工具

    可以通过输入ARGB(A代表透明度)格式或者HEX格式查看颜色,也可以进行ARGB格式和者HEX格式转换,如下图 使用C#编写,我已将源代码压缩上传 下载地址:http://files.cnblogs ...

  9. asp.net或者MVC定时自动执行某操作

    using System; using System.IO; using System.Runtime.CompilerServices; using System.Text; namespace S ...

  10. Color Blender---在线渐变色带生成器

       Color Blender是一个很有用的在线渐变色带生成器,它可以在两种颜色之间,自动生成过渡色,对网页设计师来说是一个不错的颜色调配工具.   Color Blender的使用方法很简单,你只 ...