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

题意

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

思路

设 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. quic 分析 1

    问题1:quic握手过程是怎样的? 怎样节约握手时间?握手时间多少个RTT?握手过程成涉及到哪些概念以及变量(代码) 0~1 RTT握手过程   QUIC握手的过程是需要一次数据交互,0-RTT时延即 ...

  2. 消失的两个数字(1-N缺两个数)

    给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字.你能在 O(N) 时间内只用 O(1) 的空间找到它们吗? 以任意顺序返回这两个数字均可. 示例 1: 输入: [1]输出: [2,3 ...

  3. centos7 安装telnet

    SSH Secure Shell 3.2.9 (Build 283)Copyright (c) 2000-2003 SSH Communications Security Corp - http:// ...

  4. 没找到Wkhtmltopdf,报表会被显示为html

    windows10 odoo 打印报表时提示 没找到Wkhtmltopdf,报表会被显示为html 现象 原因 没有安装Wkhtmltopdf,没有配置环境变量,odoo在电脑系统中找不到Wkhtml ...

  5. Java 获取微信小程序二维码(可以指定小程序页面 与 动态参数)

    一.准备工作 微信公众平台接口调试工具 小程序的唯一标识(appid) 小程序的密钥(secret) 二.获取access_token 打开微信公众平台接口调试工具,在参数列表中输入小程序的appid ...

  6. Django 笔记2018.2.7

    1.基础知识 1.1web服务基本原理 1.2 WSGI 目前最通用的web接口规范,python默认支持,在Django中是一个库 1.3WEB基础知识 MTV (Model Template Vi ...

  7. 8、Spring Boot任务

    1.异步任务 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring ...

  8. HarmonyOS Java UI之StackLayout布局示例

    StackLayout简介 StackLayout意为堆叠布局,用于在屏幕上保留一个区域来显示组件,实现特殊的功能.通常,堆叠布局中只应该放置一个子组件,如果存在多个子组件,则显示最新的组件.这个布局 ...

  9. Ubuntu无法telnet

    1.Ubuntu无法telnet的原因 (1)/etc/hosts被修改过 (2)防火墙没有关闭 (3)没有安装相关服务 (4)/etc/inetd.conf文件没有telnet相关内容 2.解决办法 ...

  10. kakafka - 为CQRS而生fka - 为CQRS而生

    前段时间跟一个朋友聊起kafka,flint,spark这些是不是某种分布式运算框架.我自认为的分布式运算框架最基础条件是能够把多个集群节点当作一个完整的系统,然后程序好像是在同一台机器的内存里运行一 ...