hdu 4117 -- GRE Words (AC自动机+线段树)
problem
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自动机+线段树)的更多相关文章
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
- HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)
Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...
- hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...
- HDU 5069 Harry And Biological Teacher(AC自动机+线段树)
题意 给定 \(n\) 个字符串,\(m\) 个询问,每次询问 \(a\) 字符串的后缀和 \(b\) 字符串的前缀最多能匹配多长. \(1\leq n,m \leq 10^5\) 思路 多串匹配,考 ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- 背单词(AC自动机+线段树+dp+dfs序)
G. 背单词 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使 ...
- hdu 2896 病毒侵袭 ac自动机
/* hdu 2896 病毒侵袭 ac自动机 从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉 last[]数组主要是记录具有相同后缀模式串的末尾节点编号 .本 ...
- 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- hdu 5274 Dylans loves tree(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
随机推荐
- 201521123028 《Java程序设计》第14周学习总结
1. 本周学习总结 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) 在自己建立的数据库上执行常见SQL语句(截图) 2 ...
- 201521123089 《Java程序设计》第12周学习总结
1. 本周学习总结 1. Input Stream -- 数据提供者可从其中读数据输出流:Output Stream -- 数据接收者可往其中写数据: 2. 字符流底层具体读写操作还是使用字节流: 3 ...
- select应用于read函数 超时非阻塞方式
/* * "Timed" read - timout specifies the # of seconds to wait before * giving up (5th argu ...
- Java SpringMVC小白的成长(一)
如果你是一个小白,请跟着我走,我会让你少走弯路,如果你是大牛,那么多谢大牛可以给我提提建议. 说实话,来公司这么久,一直在做的是维护与修改bug.(我的语言是php,来公司才开始接触java). 要毕 ...
- Ring3层 UNICODE_STRING
今天写驱动用到UNICODE_STRING,就在Ring3层抠了一些源代码,学习一下,不多说了上代码了 #pragma once #include <windows.h> #include ...
- 06jQuery-02-层级选择器
因为DOM结构就是层级结构,所以我们经常要根据层级关系进行选择. 1.层级选择器 $('ancestor descendant'),选择祖先中的子孙,中间留空格: $('form[name=uploa ...
- 谈一谈synchronized关键词
1.使用 java中的每一个对象都可以作为synchronized的锁进行代码同步,常见的形式 同步代码块锁是synchronized括号内的对象 普通成员方法上,锁是当前的对象,synchroniz ...
- Java并发之CyclicBarrier、CountDownLatch、Phaser
在Java多线程编程中,经常会需要我们控制并发流程,等其他线程执行完毕,或者分阶段执行.Java在1.5的juc中引入了CountDownLatch和CyclicBarrier,1.7中又引入了Pha ...
- Java Byte取值范围
Java Byte 的取值范围大家都知道(-128 ~ 127),那么-128 和 127 这两个数是怎么计算的呢? #大学知识回顾: 概念:负数的补码是该 数 绝 对 值 的 原 码 按 位 取 反 ...
- spring事务不会进行回滚的情况
if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Excep ...