和这题有些类似。
AC自动机。
字符串匹配算法,大概就是kmp,ac自动机,后缀数组,后缀自动机这么几种了。对于这题,我们很容易想到暴力dp,用kmp去匹配,总复杂度可以做到
o(n2+2∗m)
(n为字符串个数,m为所有字符串的总长),但这样还不够,超时妥妥的。
那就要考虑怎么维护这个dp了。
把自动机建好后,从前往后一个个的,去匹配。在自动机上匹配的过程中,我们可以发现,这个串走到的所有的节点,以及这些节点一路往根fail的节点,都是这个串的子串,那么以这个串结尾的获得的importance最大值,就是这所有节点的importance最大值,加上当前枚举的串的权值了。
然而,我们如果在匹配的过程中,一直fail走,那么,超时也是妥妥的,
m2
的数据还是能构造出来的。因此,我们要考虑的是怎么维护这个最大值了。
我们根据fail指针连边,会构成一颗fail树,fail树上,父亲节点是它子树所表示的串的后缀。那么对于当前串走到的某一个节点,他的最大值,就是fail树上,从他到根的这条链上的最大值了。
那么当我们得到以某一个字符串为结尾的序列,能得到的最大值时,我们能影响到哪些节点的最值呢?
很显然,fail树上,该节点的子树都会受到影响,那么就好办了。一颗子树,根据dfs序,是一段连续的区间,根据这个,我们就可以构造线段树了。区间更新,单点询问最大值就ok了。
// whn6325689
// Mr.Phoebe
// http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<50
#define speed std::ios::sync_with_stdio(false);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;
#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))
#define MID(x,y) (x+((y-x)>>1))
#define getidx(l,r) (l+r | l!=r)
#define ls getidx(l,mid)
#define rs getidx(mid+1,r)
#define lson l,mid
#define rson mid+1,r
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1;
char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
template <class T>
inline void write(T n)
{
if(n < 0)
{
putchar('-');
n = -n;
}
int len = 0,data[20];
while(n)
{
data[len++] = n%10;
n /= 10;
}
if(!len) data[len++] = 0;
while(len--) putchar(data[len]+48);
}
//-----------------------------------
const int MAXN=300010;
const int MAC=26;
char s[MAXN],ca[MAXN];
int id[MAXN],val[MAXN];
struct Node
{
int mx,la;
}t[MAXN<<1];
void build(int l,int r)
{
int idx=getidx(l,r),mid=MID(l,r);
t[idx].la=t[idx].mx=0;
if(l==r) return;
build(lson);
build(rson);
}
void pushdown(int l,int r)
{
int idx=getidx(l,r),mid=MID(l,r);
if(!t[idx].la) return;
t[ls].mx=max(t[ls].mx,t[idx].la);
t[rs].mx=max(t[rs].mx,t[idx].la);
t[ls].la=max(t[ls].la,t[idx].la);
t[rs].la=max(t[rs].la,t[idx].la);
t[idx].la=0;
}
void update(int l,int r,int L,int R,int v)
{
int idx=getidx(l,r),mid=MID(l,r);
if(L==l && r==R)
{
t[idx].la=max(t[idx].la,v);
t[idx].mx=max(t[idx].mx,v);
return;
}
pushdown(l,r);
if(R<=mid) update(l,mid,L,R,v);
else if(L>mid) update(mid+1,r,L,R,v);
else
{
update(l,mid,L,mid,v);
update(mid+1,r,mid+1,R,v);
}
}
int query(int l,int r,int pos)
{
int idx=getidx(l,r),mid=MID(l,r);
if(l==r)
return t[idx].mx;
pushdown(l,r);
if(pos<=mid) return query(l,mid,pos);
else return query(mid+1,r,pos);
}
int dfn[MAXN],rdfn[MAXN];
int timestamp;
struct Tree
{
struct Edge
{
int to,next;
}e[MAXN];
int head[MAXN],tot;
void init()
{
CLR(head,-1);tot=1;
}
void addedge(int u,int v)
{
e[tot].to=v;e[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u)
{
dfn[u]=++timestamp;
for(int i=head[u];~i;i=e[i].next)
dfs(e[i].to);
rdfn[u]=timestamp;
}
}tree;
struct AC
{
int ch[MAXN][MAC],f[MAXN],size;
void init()
{
size=0;f[0]=0;
newnode(0);
}
int newnode(int pre)
{
CLR(ch[size],0);
return size++;
}
void insert(char *S)
{
int u=0,x;
for(char *sp=S;*sp;sp++)
{
x=*sp-'a';
if(!ch[u][x]) ch[u][x]=newnode(u);
u=ch[u][x];
}
}
int que[MAXN],front,back;
void getfail()
{
int u,cur;
front=back=0;
for(int i=0;i<MAC;i++)
if(ch[0][i])
{
que[back++]=ch[0][i];
f[ch[0][i]]=0;
}
while(front<back)
{
cur=que[front++];
for(int i=0;i<MAC;i++)
{
u=ch[cur][i];
if(u)
{
que[back++]=u;
f[u]=ch[f[cur]][i];
}
else
ch[cur][i] = ch[f[cur]][i];
}
}
tree.init();
for(int i=1;i<size;i++)
tree.addedge(f[i],i);
timestamp=0;
tree.dfs(0);
}
int solve(char *S)
{
int len=strlen(S);
int u=0,now=0,ans=0;
build(1,timestamp);
for(int i=0;i<len;i++)
{
u=ch[u][S[i]-'a'];
int valu=query(1,timestamp,dfn[u]);
now=max(now,valu);
if(id[i])
{
if(val[id[i]]>0) now+=val[id[i]];
ans=max(ans,now);
update(1,timestamp,dfn[u],rdfn[u],now);
u=now=0;
}
}
return ans;
}
}ac;
int main()
{
int len,n,m,T,cas=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);
for(int j=0;j<l;j++)
s[len++]=ca[j];
id[len-1]=i;
}
ac.getfail();
printf("Case #%d: %d\n",cas++,ac.solve(s));
}
return 0;
}