稍微有点难度……不过没有孔姥爷毒瘤(

题意

给定一个单词表,每个单词有权值,取出一部分(不改变顺序)使得这部分的每一个字符串都是后一个的子串,问得到的最大权值。

思路

设 f[i] 表示选了第 i 个字符串之后得到的最大值(截止)\(f[i]=max(f[j])+w[i]\), iff s[j]是s[i]的子串且j<i;

反向建 fail 树,那么对于串 s[i] 的最后一位指向的孩子,均是包含s[i]的串,所以 s[i] 最后一位的子树中孩子节点均包含 s[i]

那么对串 s[1]~s[n] 进行计算时,可以把结果用线段树更新到子树,计算时只需考虑s[i]的每一位能得到的最大值(单点查询),

最后取 max+w[i] 为 s[i] 最大值,更新即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=3e5+10;
struct edge
{
int nxt,to;
}e[M];
char s[M];
int w[N],pos[N],tr[M][26],fail[M],rt,tot,head[M],cnt,n;
int in[M],out[M],tp,tx[M<<2],tf[M<<4],L,R,tmp; int newnode()
{
tot++; memset( tr[tot],0,sizeof(tr[tot]) );
fail[tot]=0; return tot;
} void add( int u,int v )
{
e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++;
} void insert( char *s )
{
int p=rt;
for ( int i=0; s[i]; i++ )
{
int ch=s[i]-'a';
if ( !tr[p][ch] ) tr[p][ch]=newnode();
p=tr[p][ch];
}
} void build()
{
queue<int> q; q.push(rt);
while ( !q.empty() )
{
int now=q.front(); q.pop();
if ( now!=rt ) add( fail[now],now );
for ( int i=0; i<26; i++ )
if ( tr[now][i] )
{
if ( now!=rt ) fail[tr[now][i]]=tr[fail[now]][i];
q.push( tr[now][i] );
}
else tr[now][i]=tr[fail[now]][i];
}
} void dfs( int now )
{
in[now]=++tp;
for ( int i=head[now]; i; i=e[i].nxt )
dfs( e[i].to );
out[now]=tp;
} void pushdown( int i )
{
if ( !tf[i] ) return;
int pre=tf[i];
tf[i<<1]=max( tf[i<<1],pre ); tf[i<<1|1]=max( tf[i<<1|1],pre );
tx[i<<1]=max( tx[i<<1],pre ); tx[i<<1|1]=max( tx[i<<1|1],pre );
tf[i]=0;
} int query( int l,int r,int p )
{
if ( l==r ) return tx[p];
int mid=(l+r)>>1;
pushdown(p);
if ( L<=mid ) return query( l,mid,p<<1 );
else return query( mid+1,r,p<<1|1 );
} void update( int l,int r,int p )
{
if ( L<=l && r<=R )
{
tf[p]=max( tf[p],tmp ); tx[p]=max( tx[p],tmp ); return;
}
int mid=(l+r)>>1; pushdown(p);
if ( L<=mid ) update( l,mid,p<<1 );
if ( R>mid ) update( mid+1,r,p<<1|1 );
tx[p]=max( tx[p<<1],tx[p<<1|1] );
} void init()
{
tot=-1; cnt=1; tp=0; rt=newnode();
memset( head,0,sizeof(head) ); memset( fail,0,sizeof(fail) );
memset( tx,0,sizeof(tx) ); memset( tf,0,sizeof(tf) );
} int main()
{
int T; scanf( "%d",&T );
for ( int cas=1; cas<=T; cas++ )
{
init(); scanf( "%d",&n );
for ( int i=1; i<=n; i++ )
{
scanf( "%s%d",s+pos[i-1],w+i );
pos[i]=pos[i-1]+strlen(s+pos[i-1]); insert( s+pos[i-1] );
} build(); dfs( rt ); int ans=0;
for ( int i=1; i<=n; i++ )
{
tmp=0; int now=rt;
for ( int j=pos[i-1]; j<pos[i]; j++ )
{
now=tr[now][s[j]-'a']; L=R=in[now];
int res=query( 1,tp,1 ); tmp=max( tmp,res );
}
tmp+=w[i]; ans=max( ans,tmp );
L=in[now]; R=out[now]; update( 1,tp,1 );
} printf( "Case #%d: %d\n",cas,ans );
}
}

【题解】GRE Words(UVA1502)的更多相关文章

  1. 题解 GRE Words Revenge

    题目传送门 题目大意 给出 \(m\) 次操作,分别为以下两种操作: 学习一个单词 给出一个段落,查询里面有多少个学过的单词.注意,如果学习过 \(\text{ab,bc}\) ,当前查询段落为 \( ...

  2. 2014ACM/ICPC亚洲区北京站题解

    本题解不包括个人觉得太水的题(J题本人偷懒没做). 个人觉得这场其实HDU-5116要比HDU-5118难,不过赛场情况似乎不是这样.怀疑是因为老司机带错了路. 这套题,个人感觉动态规划和数论是两个主 ...

  3. HDU 5118 GRE Words Once More!

    题目链接:HDU-5118 题意:给定一个有向无环图,每条边有一个权值.标定一些特定节点为“特殊节点”.从节点1出发到某“特殊节点”结束的路径,称为一个“GRE单词”.单词由路径上的权值组成.给定一组 ...

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

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

  5. 【题解】GREWords(AC自动机)

    [题解]GREWords(AC自动机) SP9941 GRE - GRE Words 题目大意: 给定一个由字符串构成的序列,不同位置的字符串有自己权值.现在让你选出一个子序列,使得在这个子序列中,前 ...

  6. HDU4787 GRE Words Revenge【AC自动机 分块】

    HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...

  7. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  8. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  9. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

随机推荐

  1. 运维自动化之1 - ansible 批量主机管理

    2000 - 2016 年,维护的小型机.linux刚开始的2台增加到上千台,手工检查.日常版本升级需要管理太多设备,必须通过运维自动化实现 特别是版本升级,需要到同类机器部署代码.起停设备,必须在一 ...

  2. redhat-NFS服务的配置与应用

    ---恢复内容开始--- 1.NFS服务简述 NFS实现Windows系统中资源共享的功能.NFS采用客户/服务器工作模式,客户端将服务器中的共享目录挂载到自己的某个目录下,这个目录可以与其他客户机的 ...

  3. java面试必问:多线程的实现和同步机制,一文帮你搞定多线程编程

    前言 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线 ...

  4. 如何将IDM中的进程设置进行备份

    有时候我们想用浏览器自带的下载管理器进行下载,但是一点下载却被IDM(Internet Download Manager)自动嗅探捕获并下载,还有人因为重装系统使得之前更改IDM的设置都失效,只得重新 ...

  5. 攻克弹唱第八课(吉他演奏的律动与funk音乐)

    在本期文章中,笔者将为通过Guitar Pro 7吉他打谱软件与大家分享一下吉他律动与funk音乐的经验. 想必正在看这篇文章的进阶者和高手,都会考虑这样一个问题.我辛辛苦苦练习的大段solo和指弹曲 ...

  6. 在家看电影音效太差?Boom 3D帮你轻松升级

    新片上映后,很多人都会选择去电影院观看,一是为了第一时间看到电影,还有一个原因就是电影院的音效往往可以让人身临其境,更好地感受电影的氛围.那如果在家刷片我们该怎么办呢? 我们可以使用Boom 3D这款 ...

  7. 如何清理MacBook电脑缓存?

    使用Mac电脑的用户都知道,Mac其空间硬盘大多数都是只有128G以及256G的规格,而用惯了win系统基本都是超过512G的硬盘的用户,转手来使用Mac电脑,就不得不接受这一硬伤问题. 用户往往再怎 ...

  8. 如何使用系统清理缓存软件优化MacBook

    在我们使用我们的Mac一定的时间后,总是不可避免的出现Mac内存不足的情况,所以清理垃圾软件也就成为了我们电脑里必不可少的软件.苹果软件商店中有很多各有不同的清理垃圾软件,但我们往往很难从这一大堆软件 ...

  9. word选择+快捷键

    统一修改红色章节标题字体:将鼠标放置在章节标题中,前提是各章节标题采用的格式是一样的,单击"选择"-"选择格式相似的文本"即可全部选中进行设置 如下图,章节标题 ...

  10. Jmeter(一)发送http请求

    Jmeter中发请求的步骤 1.添加线程组 2.添加http消息头管理器 3.添加http请求 一.线程组: 1.添加路径: 2.字段解释 ①线程数(Number of Threads): : 设置发 ...