hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843
此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后缀
然后更新其影响的字符串的方法,即区间更新,维护最大值,用线段树优化。
而其可以影响的字符串为其在fail树中的子树节点
此题一直MLE,调了一下午+晚上。最后发现。
(1)ac自动机中的节点开始直接初始化,应动态初始化(也终于理解了许多人那么做)
(2)还有用vector表示树边时,一开始初始clear,也会耗很多内存。
(3)线段树开始直接初始化CLR(smax, 0)CLR(cov, 0),由于数组比较大,内存耗较大
最后,ac自动机节点动态初始化,用链表模拟表示树边,线段树动态build,终于有MLE变成了wa
怒重敲,终于ac了
PS:一开始使用后缀数组ac的,数据水了。。。
不过ac自动机2s+,后缀数组8s+
ac自动机:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std; #define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i >= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(a, v) memset(a, v, sizeof(a))
#define PB push_back
#define MP make_pair
typedef long long LL;
const int INF = 0x3f3f3f3f; #define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1 const int MAX = 333333;
const int SIG = 26; struct Edge{
int to, next;
}adj[MAX * 2];
int adj_cnt;
int head[MAX];
void adj_init()
{
adj_cnt = 0;
CLR(head, -1);
}
void add_edge(int x, int y)
{
adj[adj_cnt].to = y;
adj[adj_cnt].next = head[x];
head[x] = adj_cnt++;
} int tl[MAX], tr[MAX];
int tot; char ca[MAX], s[MAX];
int id[MAX];
int val[MAX]; int smax[MAX << 2], cov[MAX << 2];
void update_cov(int rt, int x)
{
smax[rt] = max(smax[rt], x);
cov[rt] = max(cov[rt], x);
}
void up(int rt)
{
smax[rt] = max(smax[rt << 1], smax[rt << 1 | 1]);
}
void down(int rt)
{
if (cov[rt])
{
update_cov(rt << 1, cov[rt]); update_cov(rt << 1 | 1, cov[rt]);
cov[rt] = 0;
}
}
void build(int l, int r, int rt)///!!!
{
smax[rt] = cov[rt] = 0;
if (l == r) return ;
int m = (l + r) >> 1;
build(lson); build(rson);
up(rt);
}
void update(int L, int R, int x, int l, int r, int rt)
{
if (L <= l && r <= R)
{
update_cov(rt, x);
return ;
}
down(rt);
int m = (l + r) >> 1;
if (L <= m) update(L, R, x, lson);
if (R > m) update(L, R, x, rson);
up(rt);
}
int query(int p, int l, int r, int rt)
{
if (l == r) return smax[rt];
down(rt);
int m = (l + r) >> 1;
if (p <= m) return query(p, lson);
else return query(p, rson);
} struct AC{
int ch[MAX][SIG];
int f[MAX];
int sz;
int newnode()///!!!
{
CLR(ch[sz], 0);
return sz++;
}
void init()
{
sz = 0;
newnode();
}
int idx(char c) { return c-'a'; }
void insert(char *s)
{
int u=0,n=strlen(s);
for(int i=0;i<n;i++)
{
int c=idx(s[i]);
if(!ch[u][c]) ch[u][c] = newnode();
u = ch[u][c];
}
}
void getFail()
{
queue<int> q;
f[0] = 0;
for(int c = 0; c < SIG; c++)
{
int u = ch[0][c];
if(u) { f[u] = 0; q.push(u); }
} while(!q.empty())
{
int r = q.front(); q.pop();
for(int c = 0; c < SIG; c++)
{
int u = ch[r][c];
if(!u) { ch[r][c] = ch[f[r]][c]; continue; }
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
}
}
}
void dfs(int u, int fa)
{
tl[u] = ++tot;
for (int r = head[u]; r != -1; r = adj[r].next)
{
int v = adj[r].to;
if (v != fa) dfs(v, u);
}
tr[u] = tot;
}
void makeTree()
{
adj_init();
for (int i = 1; i < sz; i++)///
{
add_edge(i, f[i]); add_edge(f[i], i);
}
tot = 0;
dfs(0, -1);
}
int solve(char *s)
{
int len = strlen(s);
int u = 0;
int now, ans;
ans = now = 0;
build(1, tot, 1);
for (int i = 0; i < len; i++)
{
u = ch[u][s[i] - 'a'];
int valu = query(tl[u], 1, tot, 1);
now = max(now, valu);
if (id[i])
{
if (val[id[i]] > 0) now += val[id[i]];
ans = max(ans, now);
update(tl[u], tr[u], now, 1, tot, 1); u = now = 0;
}
}
return ans;
}
}ac; int main()
{
int len;
int n, m;
int T, nc;
nc = 1;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
len = 0;
ac.init();
CLR(id, 0);
for (int i = 1; i <= n;i++)
{
scanf("%s%d", ca, &val[i]);
ac.insert(ca);
int l = strlen(ca);
REP(j, l)
{
s[len++] = ca[j];
}
id[len - 1] = i;
}
ac.getFail();
ac.makeTree();
printf("Case #%d: %d\n", nc++, ac.solve(s));
}
}
后缀数组:
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FD(i, b, a) for(int i = (b) - 1; i >= (a); --i)
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//STL
#define SZ(V) (int)V.size()
#define PB push_back
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RIV(n, m, k, p) scanf("%d%d%d%d", &n, &m, &k, &p)
#define RV(n, m, k, p, q) scanf("%d%d%d%d%d", &n, &m, &k, &p, &q)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 1000000000;
const double eps = 1e-10; const int MAXN=110000 * 4; int wa[MAXN], wb[MAXN], wv[MAXN], wn[MAXN];
char r[MAXN];
int a[MAXN], sa[MAXN], rank[MAXN], height[MAXN];
int idx[MAXN];
int val[20010];
int len[20010];
int sumlen[20010];
int dp[20010]; int cmp(int *r, int a, int b, int k)
{
return r[a] == r[b] && r[a + k] == r[b + k];
}
void build_sa(int *r, int *sa, int n, int m)
{
int i, j, p;
int *x = wa, *y = wb, *t;
for (i = 0; i < m; i++) wn[i] = 0;
for (i = 0; i < n; i++)wn[x[i] = r[i]]++;///
for (i = 1; i < m; i++) wn[i] += wn[i - 1];
for (i = n - 1; i >= 0; i--) sa[--wn[x[i]]] = i; for (p = 1, j = 1; p < n; j <<= 1, m = p)
{
for (p = 0, i = n - j; i < n; i++) y[p++] = i;
for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j; for (i = 0; i < m; i++) wn[i] = 0;
for (i = 0; i < n; i++) wn[wv[i] = x[y[i]]]++;///
for (i = 1; i < m; i++) wn[i] += wn[i - 1];
for (i = n - 1; i >= 0; i--) sa[--wn[wv[i]]] = y[i]; t = x; x = y; y = t;
x[sa[0]] = 0; p = 1;
for (i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
}
} void getHeight(int *r, int *sa, int n)
{
int i, j, k = 0;
for (i = 1; i <= n; i++)
{
rank[sa[i]] = i;
height[i] = 0;
}
for (i = 0; i < n; i++)
{
if (k) k--;
j = sa[rank[i] - 1];
while (r[i + k] == r[j + k]) k++;
height[rank[i]] = k;
}
} int getid(int x)
{
return idx[sa[x]];
}
int solve(int t, int n)
{
int sum = 0;
FE(i, 1, t)
{
dp[i] = val[i];
sumlen[i] = sum;
sum += len[i] + 1;
}
int nowi;
FED(i, t, 1)
{
nowi = sumlen[i]; int lmin = INF;
for (int j = rank[nowi] + 1; j <= n; j++)
{
lmin = min(lmin, height[j]);
if (lmin < len[i]) break;
if (nowi < sa[j])
dp[i] = max(dp[i], val[i] + dp[getid(j)]);
}
lmin = INF;
for (int j = rank[nowi] - 1; j > 0; j--)
{
lmin = min(lmin, height[j + 1]);
if (lmin < len[i]) break;
if (nowi < sa[j])
dp[i] = max(dp[i], val[i] + dp[getid(j)]);
}
}
int ans = 0;
FE(i, 1, t) ans = max(ans, dp[i]);
return ans;
} int main()
{
int test;
int t, n, m;
int ncase = 1;
RI(test);
while (test--)
{
n = 0;
m = 256;
CLR(idx, 0);
RI(t);
FE(i, 1, t)
{
RS(r);
RI(val[i]);
int l = len[i] = strlen(r);
REP(j, l)
{
a[n] = (int)r[j];
idx[n++] = i;
}
a[n++] = m++;
}
a[--n] = 0; --m;
build_sa(a, sa, n + 1, m);
getHeight(a, sa, n); printf("Case #%d: %d\n", ncase++, solve(t, n));
}
return 0;
}
hdu 4117 GRE Words (ac自动机 线段树 dp)的更多相关文章
- hdu 4117 -- GRE Words (AC自动机+线段树)
题目链接 problem Recently George is preparing for the Graduate Record Examinations (GRE for short). Obvi ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
- HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)
Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...
- 背单词(AC自动机+线段树+dp+dfs序)
G. 背单词 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使 ...
- hdu 4057--Rescue the Rabbit(AC自动机+状压DP)
题目链接 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for ...
- HDU 5069 Harry And Biological Teacher(AC自动机+线段树)
题意 给定 \(n\) 个字符串,\(m\) 个询问,每次询问 \(a\) 字符串的后缀和 \(b\) 字符串的前缀最多能匹配多长. \(1\leq n,m \leq 10^5\) 思路 多串匹配,考 ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- hdu 2896 病毒侵袭 ac自动机
/* hdu 2896 病毒侵袭 ac自动机 从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉 last[]数组主要是记录具有相同后缀模式串的末尾节点编号 .本 ...
- HDU 3016 Man Down (线段树+dp)
HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
随机推荐
- java的JCombobox实现中国省市区三级联动
源代码下载:点击下载源代码 用xml存储中国各大城市的数据. xml数据太多了就不贴上了,贴个图片: 要解释xml,添加了一个jdom.jar,上面的源代码下载里面有. 解释xml的类: packag ...
- 11997 - K Smallest Sums(优先队列)
11997 - K Smallest Sums You’re given k arrays, each array has k integers. There are kk ways to pick ...
- 杭电 HDU 1242 Rescue
http://acm.hdu.edu.cn/showproblem.php?pid=1242 问题:牢房里有墙(#),警卫(x)和道路( . ),天使被关在牢房里位置为a,你的位置在r处,杀死一个警卫 ...
- git 使用过程(四、回退版本)
1.查看修改历史 命令:git log 如果嫌内容太多 可以加参数 --pretty=oneline (图一) 2.回退 命令:git reset --hard HEAD^ HEAD:代表本 ...
- 设置outlook自动回复
当有同事需要出差时,或者不能即时回复邮件时,可用此功能. 下面列出设置步骤: 1. 首先,在桌面新建一个用以保存模板的文件夹,例如:emaii. 2. 新建一封邮件,输入你要自动回复的内容.另存为 ...
- Codeforces Round #316 (Div. 2A) 570A Elections
题目:Click here #include <bits/stdc++.h> using namespace std; typedef long long ll; const int IN ...
- IP数据包结构
Linux 网络编程——IP 数据报格式详解 http://www.linuxidc.com/Linux/2015-04/116149.htm
- 一个开源Delphi分类组件推荐网页
https://github.com/Fr0sT-Brutal/awesome-delphi
- pojg487-3279电话号码转换(字符映射)
http://poj.grids.cn/practice/2974 注意输入中连字符可以任意添加和删除. 描述企业喜欢用容易被记住的电话号码.让电话号码容易被记住的一个办法是将它写成一个容易记住的单词 ...
- 2、Zookeeper集群搭建、命令行Client操作
zookeeper 集群最好是奇数台: 5台允许挂掉2台 4台只能允许挂掉1台 zjtest7-redis:/opt/zookeeper/bin# ./zkServer.sh status ZooKe ...