这题我的代码在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. mysql开启日志

    在 centos 5 下,  在 mysld 下面,添加一行 log=/var/log/mysql.log 然后执行如下命令 touch /var/log/mysql.logchmod 777 /va ...

  2. INPC & RaizePropertyChanged in mvvmlight

    INPC & RaizePropertyChanged in mvvmlight In WPF app, MvvM Framework, we binding the UIElement fr ...

  3. 阅读verilog程序总结

    1.写程序先直接写出时钟信号 //-----------------产生串行时钟scl,为输入时钟的二分频--------- always@(negedge clk)//二分频表示频率小了,周期大了 ...

  4. 60.ISE PhysDesignRules ERROR

    PhysDesignRules:2100 - Issue with pin connections and/or configuration on block:<U_ila_pro_0/U0/I ...

  5. UIToolbar swift

    // // ViewController.swift // UILabelTest // // Created by mac on 15/6/23. // Copyright (c) 2015年 fa ...

  6. Android -- TouchEvent的分发和截获方式

    Android系统中的每个ViewGroup的子类都具有下面三个和TouchEvent处理密切相关的方法: public boolean dispatchTouchEvent(MotionEvent ...

  7. Linux学习之路--启动VNC服务

    我的Linux是Fedora 13,安装方法如下: 1.打开终端,执行 # yum install -y tigervnc tigervnc-server 2.编辑/etc/sysconfi/vncs ...

  8. CS小分队第一阶段冲刺站立会议(5月6日)

    冲刺阶段第一天 今日任务:完成游戏2048退出自动保存和进入自动读取功能,完善其他功能.

  9. JS获取字符串长度(英文占1个字符,中文汉字占2个字符)

    方法一: String.prototype.gblen = function() { var len = 0; for (var i = 0; i < this.length; i++) { i ...

  10. Phantom omini设备开发流程

    最近在忙着做毕业设计,我的毕业设计是做力觉临场感的,所以在力反馈设备Phantom Omini,由于整个设备是国外的国内的资料很少,我是14年拿到这个设备的但是真的是在开发是在16年了,中间有很多事没 ...