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

题意

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

思路

设 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. 在 JavaScript 中,我们能为原始类型添加一个属性或方法吗?

    原始类型的方法 JavaScript 允许我们像使用对象一样使用原始类型(字符串,数字等).JavaScript 还提供了这样的调用方法.我们很快就会学习它们,但是首先我们将了解它的工作原理,毕竟原始 ...

  2. Socket listen 简要分析

    #include <sys/types.h> /* See NOTES */#include <sys/socket.h>int listen(int sockfd, int ...

  3. ssh2中的添,删,查,改。

    1.spring封装的HibernateTemplate类的一些操作方法. 2.session提供的根据主键ID进行添.删.查.改的基本方法. 由session得到的hql语句 由session得到的 ...

  4. 常见mysql后台线程

     1.IO THREAD  MySQL有很多后台线程 其中包括了负责IO的相关线程IO THREAD 1. 参数innodb_write_io_threads  写线程 默认四个,负责数据块的写入 2 ...

  5. 痞子衡嵌入式:JLink Script文件基础及其在IAR下调用方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是JLink Script文件基础及其在IAR下调用方法. JLink可以说是MCU开发者最熟悉的调试工具了,相比于其他调试器(比如DAP ...

  6. php获取字符串长度

    function len($zfc){ $arr = []; $len = mb_strlen($zfc); for ($i = 0; $i < $len; $i++) { array_push ...

  7. git key生成

    1.打开git ssh 2.检查home目录的ssh目录是否存在,没有创建一个,mkdir ~/.ssh 3.运行命名:ssh-keygen -t rsa -C "你的邮箱", 如 ...

  8. ntfs和fat32的区别

    ntfs和fat32是两种不同的磁盘文件系统格式,虽然他们有一定的相似点,但还是具有很大的差异.今天,小编就带大家了解一下ntfs和fat32的区别. 图1 :u盘 一.分区容量 fat32能够有效管 ...

  9. 「CSP-S 2020」动物园

    description luogu loj(暂无数据) solution 这道题作为T2,对选手们考试开始后先通看一遍所有题目的好习惯,以及判断究竟谁才是真正的签到题的重要能力进行了较好的锻炼, 特别 ...

  10. img元素的联用

    img元素的常用属性: src属性:资源地址 alt属性:当图片资源失效时,将出现该属性的设置的文字 最简单的联动: 和a元素联用(直接用a标签套) <a href="https:// ...