这题我的代码在hdu上AC,在uva上WA。

题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串。问d值的和最大是多少。 (1≤n≤2×10^4 ,串的总长度<=3*10^5)

题解:

这题一开始我的方向就错了,想了很久d[x][y]表示在AC自动机上的节点x、下一个串要大于y的dp。然而这样做数组要10^4*10^5=10^9级别,开都开不了,妥妥超时。

后来看了一眼题解。。。觉得自己智商真是感人。。。

用f[i]表示以第i个串为结尾的时候最大的d值,这样做就可以知道在AC自动机上的位置、当前在第几个串。

f[i]=max(f[j])+w[i],j所代表的串为i的子串。

现在我们要快速知道子串:

1.

建立AC自动机,然后将fail反向建立fail树。

对于fail树上某个点来说,它的祖先所代表的串必为它的子串(通过一直fail可以到达的点)

fail树上做一遍dfs求出dfn,就可以做到线性时间维护子树的最值。

2.

字符串x在fail树上求到的子串是除了x本身、在其他字符串中求到的子串,但是x自己的某一段也是自己的子串。所以在AC自动机上走到x的末尾节点,所经过的路程每一个点所代表的字符串也是x的子串。

对于每一个i,我把已求出来的f[i]放到failtree上它所对应的点,然后i的整个子树的最大值都要更新一遍。所以我们要开一棵线段树来维护,用failtree的dfn来作为线段树的下标,维护区间最大值。

求f[i]的时候就在AC自动机上走一遍字符串i,对于每个经过的点询问一遍它的值-------解决了第二种子串

询问i的末尾节点的值-----解决了第一种子串,因为在i前面、failtree上是i的祖先的点已经更新了i。

然后取最值,放入failtree上,更新failtree的子树即可。

 //hdu4117

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std; const int N=,M=,S=;
int n,num,cnt_dfn,cnt_seg,len,w[M],last[M],first[N],dfn[N],next_dfn[N];
char s[N];
struct trie_node{
int fa,fail,son[];
}a[N];
struct fail_node{
int x,y,next;
}b[N];
struct seg_node{
int lc,rc,l,r,d,lazy;
}t[*N];
queue<int> q; int maxx(int x,int y){return x>y ? x:y;} void clear(int x)
{
a[x].fail=a[x].fa=;
memset(a[x].son,,sizeof(a[x].son));
} void ins(int x,int y)
{
b[++len].x=x;b[len].y=y;
b[len].next=first[x];first[x]=len;
} void read_trie(int id)
{
scanf("%s%d",s,&w[id]);
int x=,l=strlen(s);
for(int i=;i<l;i++)
{
// if(!(s[i]>='a' && s[i]<='z')) while(1) ;
int ind=s[i]-'a'+;
if(!a[x].son[ind])
{
num++;
clear(num);
a[x].son[ind]=num;
a[num].fa=x;
}
x=a[x].son[ind];
}
last[id]=x;
} void build_AC_failtree()
{
while(!q.empty()) q.pop();
for(int i=;i<=S;i++)
if(a[].son[i]) q.push(a[].son[i]);
while(!q.empty())
{
int x=q.front();q.pop();
int fail=a[x].fail;
for(int i=;i<=S;i++)
{
if(a[x].son[i])
{
a[a[x].son[i]].fail=a[fail].son[i];
q.push(a[x].son[i]);
}
else a[x].son[i]=a[fail].son[i];
}
}
for(int i=;i<=num;i++)
ins(a[i].fail,i);
} void make_dfn(int x)
{
dfn[x]=++cnt_dfn;
for(int i=first[x];i;i=b[i].next) make_dfn(b[i].y);
next_dfn[x]=cnt_dfn;
} int build_segtree(int l,int r)
{
cnt_seg++;
int x=cnt_seg;
t[x].l=l;t[x].r=r;t[x].d=;
t[x].lc=t[x].rc=;t[x].lazy=;//debug 原本根节点是0,但是这里也是0,就WA了
if(l!=r)
{
int mid=(l+r)>>;
t[x].lc=build_segtree(l,mid);
t[x].rc=build_segtree(mid+,r);
}
return x;
} void updata(int x)
{
if(!t[x].lazy) return;
int lazy=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
t[x].d=maxx(t[x].d,lazy);
t[x].lazy=;
t[lc].lazy=maxx(t[lc].lazy,lazy);//debug****
t[rc].lazy=maxx(t[rc].lazy,lazy);//debug****
} void change(int x,int l,int r,int d)
{
updata(x);
if(t[x].l==l && t[x].r==r) {t[x].lazy=d;return;}
int lc=t[x].lc,rc=t[x].rc;
int mid=(t[x].l+t[x].r)>>;
if(r<=mid) change(lc,l,r,d);
else if(l>mid) change(rc,l,r,d);
else
{
change(lc,l,mid,d);
change(rc,mid+,r,d);
}
updata(lc);
updata(rc);
t[x].d=maxx(t[lc].d,t[rc].d);
} int query(int x,int y)
{
if(t[x].lazy) updata(x);
if(t[x].l==t[x].r) return t[x].d;
int lc=t[x].lc,rc=t[x].rc;
int mid=(t[x].l+t[x].r)>>;
if(y<=mid) return query(lc,y);
if(y>mid) return query(rc,y);
} int dp_AC(int x,int now,int id)
{
if(x==) return now;
return dp_AC(a[x].fa,maxx(now,query(,dfn[x])),id);
} int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T,TT=;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
num=;len=;cnt_dfn=-;cnt_seg=;//原本cnt_seg=-1,根节点=0,后来cnt_seg改成0,根节点=1
clear();
memset(first,,sizeof(first));
for(int i=;i<=n;i++) read_trie(i);
build_AC_failtree();
make_dfn();
build_segtree(,num);
//dp
int mx=,x,fx;
for(int i=;i<=n;i++)
{
x=last[i];
fx=dp_AC(x,,i)+w[i];
change(,dfn[x],next_dfn[x],fx);
mx=maxx(mx,fx);
}
printf("Case #%d: %d\n",++TT,mx);
}
}

【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机的更多相关文章

  1. [USACO2005][POJ3171]Cleaning Shifts(DP+线段树优化)

    题目:http://poj.org/problem?id=3171 题意:给你n个区间[a,b],每个区间都有一个费用c,要你用最小的费用覆盖区间[M,E] 分析:经典的区间覆盖问题,百度可以搜到这个 ...

  2. HDU4719-Oh My Holy FFF(DP线段树优化)

    Oh My Holy FFF Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) T ...

  3. UVA-1322 Minimizing Maximizer (DP+线段树优化)

    题目大意:给一个长度为n的区间,m条线段序列,找出这个序列的一个最短子序列,使得区间完全被覆盖. 题目分析:这道题不难想,定义状态dp(i)表示用前 i 条线段覆盖区间1~第 i 线段的右端点需要的最 ...

  4. zoj 3349 dp + 线段树优化

    题目:给出一个序列,找出一个最长的子序列,相邻的两个数的差在d以内. /* 线段树优化dp dp[i]表示前i个数的最长为多少,则dp[i]=max(dp[j]+1) abs(a[i]-a[j])&l ...

  5. 完美字符子串 单调队列预处理+DP线段树优化

    题意:有一个长度为n的字符串,每一位只会是p或j.你需要取出一个子串S(注意不是子序列),使得该子串不管是从左往右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个数.如果你的子串是最长的,那 ...

  6. Contest20140906 ProblemA dp+线段树优化

    Problem A 内存限制 256MB 时间限制 5S 程序文件名 A.pas/A.c/A.cpp 输入文件 A.in 输出文件 A.out 你有一片荒地,为了方便讨论,我们将这片荒地看成一条直线, ...

  7. POJ 3171.Cleaning Shifts-区间覆盖最小花费-dp+线段树优化(单点更新、区间查询最值)

    Cleaning Shifts Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4721   Accepted: 1593 D ...

  8. 题解 HDU 3698 Let the light guide us Dp + 线段树优化

    http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...

  9. 省选模拟赛 4.26 T1 dp 线段树优化dp

    LINK:T1 算是一道中档题 考试的时候脑残了 不仅没写优化 连暴力都打挂了. 容易发现一个性质 那就是同一格子不会被两种以上的颜色染.(颜色就三种. 通过这个性质就可以进行dp了.先按照左端点排序 ...

随机推荐

  1. 1.Knockout.Js(简介)

    前言 最近一段时间在网上经常看到关于Knockout.js文章,于是自己就到官网看了下,不过是英文的,自己果断搞不来,借用google翻译了一下.然后刚刚发现在建立asp.net mvc4.0的应用程 ...

  2. 发现了一个制作iOS图标的利器

    我制作的第一个Swift Demo已经将近完工,今天的任务便是给它添加图标.不过Xcode中对图标尺寸的要求还真是严苛,若是制作iPhone和iPad通用的应用,总共需要12种尺寸的图标,这对于美工功 ...

  3. iOS中远程推送实现—在Apple的生产环境上测试Push Notifications功能

    1.在“Provisioning Profiles”中点击“Add”按钮. 2.在“What type of provisioning profile do you need?”页面中选择“Distr ...

  4. IIS 404.17 错误解决方案

    操作方法:在管理员身份打开命令行,运行以下命令: C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis -i

  5. sql总结

    sql总结 sql总结 where字句中使用的运算符 定义外键 定义主键 多表联合查询 统计函数 数据类型 sql语句格式 转换函数 null函数 运算符 日期 求某天是星期几 日期天数差 next_ ...

  6. java卡与native卡的区别

      JavaCard Native 功能特性 开发语言 l  纯面向对象的Java语言的子集. Java语言先进灵活,开发调试速度快,实现灵活. l  Java没有指针,并且有内部安全机制可以有效的避 ...

  7. 团队作业php

    <?php$kouwei=$_GET["select"];$daxiao=$_GET["RadioGroup1"];$peiliao=$_GET[&quo ...

  8. Liferay JSP中常用的标签

    (本文转载自http://www.cnblogs.com/edwardlauxh/archive/2010/03/26/1918614.html) 在Liferay框架中拥有它自身的标签,虽然Port ...

  9. 关于网站IIS日志分析搜索引擎爬虫说明

    正文:iis默认的日志文件在C:\WINDOWS\system32\LogFiles中,下面是Seoer惜缘的服务器日志,通过查看,就可以了解搜索引擎蜘蛛爬行经过,如: 2008-08-19 00:0 ...

  10. 尝试用Uplodify

    尝试用Uplodify     Uplodify官方 前台index代码: @{ Layout = null; } <script src="~/Scripts/jquery-1.8. ...