由易到难
http://blog.youkuaiyun.com/gyarenas/article/details/9315319
GRE Words hdu 4117
http://acm.hdu.edu.cn/showproblem.php?pid=4117
这题本来的做法是ac自动机优化dp,然而hdu加入了新的数据,估计构造了一些会导致fail链很长的数据,以前的做法会TLE,这就又需要我们维护fail树,用线段树维护fail树的dfs序列,支持单点修改区间求最值。需要注意的是当fail链比较短时(比如这题的原始数据),用线段树维护做法反而耗时更长。
一开始交上去各种优化各种MLE,后来发现原来是AC自动机初始化一下把整个数组置空了,特意找了篇oj判MLE的方法http://blog.youkuaiyun.com/a775700879/article/details/12521915,从这种情况来看,hdu用的方法应该和bnuoj一样
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <ctime>
#include <bitset>
#include <iomanip>
#pragma comment(linker, "/STACK:102400000,102400000")
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;
using std::ios;
using std::make_heap;
using std::push_heap;
using std::pop_heap;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UN;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
typedef long double LF;
const int MAXN(300010);
const int MAXM(20010);
const int MAXE(2100010);
const int MAXK(6);
const int HSIZE(1313131);
const int SIGMA_SIZE(26);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(1e13);
const int INV(-10000);
const int MOD(1000000007);
const double EPS(1e-7);
const LF PI(acos(-1.0));
template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;}
template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;}
template<typename T> inline T ABS(T a){return a < 0? -a: a;}
template<typename T> inline bool EZ(T a){return ABS(a) < EPS;}
struct SGT{
int val[MAXN << 2];
inline int ls(int rt){return rt << 1;}
inline int rs(int rt){return (rt << 1)|1;}
inline void push_up(int rt){val[rt] = max(val[ls(rt)], val[rs(rt)]);}
void build(int l, int r, int rt){
val[rt] = -INFI;
if(l == r) return;
int m = (l+r) >> 1;
build(l, m, ls(rt));
build(m+1, r, rs(rt));
}
void update(int l, int r, int rt, int qi, int qv){
if(l == r){
checkmax(val[rt], qv);
return;
}
// push_down(rt);
int m = (l+r) >> 1;
if(qi <= m) update(l, m, ls(rt), qi, qv);
else update(m+1, r, rs(rt), qi, qv);
push_up(rt);
}
int query(int l, int r, int rt, int ql, int qr){
if(ql <= l && qr >= r) return val[rt];
// push_down(rt);
int m = (l+r) >> 1;
int ret = -INFI;
if(ql <= m) checkmax(ret, query(l, m, ls(rt), ql, qr));
if(qr > m) checkmax(ret, query(m+1, r, rs(rt), ql, qr));
return ret;
}
} sgt;
int left[MAXN], right[MAXN], ind;
struct TREE{
int *first, *v, *next; //内存优化,先借用线段树的内存
int rear;
void init(int n){
first = sgt.val;
v = sgt.val+MAXN;
next = sgt.val+2*MAXN;
memset(first, -1, sizeof(first[0])*n);
rear = 0;
}
void insert(int tu, int tv){
v[rear] = tv;
next[rear] = first[tu];
first[tu] = rear++;
}
void dfs(int u){
left[u] = ++ind;
for(int i = first[u]; ~i; i = next[i])
dfs(v[i]);
right[u] = ind;
}
} tree;
int po[MAXM], sco[MAXM];
int front, back;
struct AC{
int f[MAXN], ch[MAXN][SIGMA_SIZE], size;
void init(){
memset(ch[0], 0, sizeof(ch[0])); // !!!memset(ch[0], 0, sizeof(ch));
size = 1;
}
void insert(char *sp, int i){
int rt = 0;
for(; *sp; ++sp){
int id = *sp-'a';
if(!ch[rt][id]){
memset(ch[size], 0, sizeof(ch[size]));
ch[rt][id] = size++;
}
rt = ch[rt][id];
}
po[i] = rt;
}
void construct(){
front = back = 0;
tree.init(size);
for(int i = 0; i < SIGMA_SIZE; ++i)
if(ch[0][i]){
f[ch[0][i]] = 0;
tree.insert(0, ch[0][i]);
left[back++] = ch[0][i];
}
while(front < back){
int cur = left[front++];
for(int i = 0; i < SIGMA_SIZE; ++i){
int u = ch[cur][i];
if(u){
f[u] = ch[f[cur]][i];
tree.insert(f[u], u);
left[back++] = u;
}
else
ch[cur][i] = ch[f[cur]][i];
}
}
ind = 0;
tree.dfs(0);
}
} ac;
char str[MAXN+MAXM];
char *tst[MAXM];
int main(){
// freopen("d:\\in.txt", "r", stdin);
// freopen("d:\\out.txt", "w", stdout);
int TC, n_case(0);
scanf("%d", &TC);
while(TC--){
ac.init();
int n;
scanf("%d", &n);
tst[0] = str;
for(int i = 0; i < n; ++i){
scanf("%s%d", tst[i], sco+i);
tst[i+1] = tst[i]+strlen(tst[i])+1;
ac.insert(tst[i], i);
}
ac.construct();
sgt.build(1, ind, 1);
int ans = 0;
for(int i = n-1; i >= 0; --i){
int temp = sgt.query(1, ind, 1, left[po[i]], right[po[i]]);
checkmax(temp, 0);
temp += sco[i];
int rt = 0;
for(char *sp = tst[i]; *sp; ++sp){
int id = *sp-'a';
rt = ac.ch[rt][id];
sgt.update(1, ind, 1, left[rt], temp);
}
checkmax(ans, temp);
}
printf("Case #%d: %d\n", ++n_case, ans);
}
return 0;
}
阿狸的打字机
http://blog.youkuaiyun.com/gyarenas/article/details/9260235