题目大意:
给定n个字符串,要求按顺序取一些字符串,满足后一个字符串是前一个字符串的子串,要求使得取出的权值和最大。
解题思路:
先建出AC自动机,设
f[i]
表示选第
i
个串做结尾的最大价值,那么有:
找
max(f[j])
最朴素的方法就是沿着单词
i
的每个节点的fail链找最大的
不妨考虑把所有fail指针倒过来建成一棵fail树,那么每更新一个节点
i
的
还有这题卡空间到爆,千万别用vector或queue或memset。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=300005,M=20005;
struct node
{
int son[26],fail;
inline void init()
{
fail=0;
memset(son,0,sizeof(son));
}
}tr[N];
int T,n,tot,idx,in[N],out[N],w[M],pos[M],mx[N<<2],tag[N<<2];
int ecnt,first[N],nxt[N],to[N],q[N];
char s[N];
inline void add(int x,int y)
{
nxt[++ecnt]=first[x],first[x]=ecnt,to[ecnt]=y;
}
inline void Insert(char *s)
{
int len=strlen(s),po=1;
for(int i=0;i<len;i++)
{
if(!tr[po].son[s[i]-'a'])tr[tr[po].son[s[i]-'a']=++tot].init();
po=tr[po].son[s[i]-'a'];
}
}
inline void build_fail()
{
int head=0,tail=1;
q[1]=1;
while(head<tail)
{
int u=q[++head];
for(int i=0;i<26;i++)
{
int v=tr[u].fail,w=tr[u].son[i];
while(!tr[v].son[i])v=tr[v].fail;
v=tr[v].son[i];
if(w)tr[w].fail=v,q[++tail]=w;
else tr[u].son[i]=v;
}
}
}
inline void dfs(int u)
{
in[u]=++idx;
for(int e=first[u];e;e=nxt[e])dfs(to[e]);
out[u]=idx;
}
inline void build(int k,int l,int r)
{
mx[k]=tag[k]=0;
if(l==r)return;
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
}
inline void pushdown(int k)
{
mx[k<<1]=max(mx[k<<1],tag[k]);
mx[k<<1|1]=max(mx[k<<1|1],tag[k]);
tag[k<<1]=max(tag[k<<1],tag[k]);
tag[k<<1|1]=max(tag[k<<1|1],tag[k]);
tag[k]=0;
}
inline int query(int k,int l,int r,int p)
{
if(l==r)return mx[k];
if(tag[k])pushdown(k);
int mid=l+r>>1;
if(p<=mid)return query(k<<1,l,mid,p);
else return query(k<<1|1,mid+1,r,p);
}
inline void modify(int k,int l,int r,int x,int y,int v)
{
if(x==l&&y==r)
{
mx[k]=max(mx[k],v);
tag[k]=max(tag[k],v);
return;
}
if(tag[k])pushdown(k);
int mid=l+r>>1;
if(y<=mid)modify(k<<1,l,mid,x,y,v);
else if(x>mid)modify(k<<1|1,mid+1,r,x,y,v);
else modify(k<<1,l,mid,x,mid,v),modify(k<<1|1,mid+1,r,mid+1,y,v);
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
int main()
{
//freopen("lx.in","r",stdin);
scanf("%d",&T);
for(int C=1;C<=T;C++)
{
scanf("%d",&n);
tot=1;tr[1].init();
for(int i=0;i<26;i++)tr[0].son[i]=1;
pos[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%s%d",s+pos[i-1],&w[i]);
pos[i]=strlen(s);
Insert(s+pos[i-1]);
}
build_fail();
ecnt=0;
for(int i=1;i<=tot;i++)first[i]=0;
for(int i=2;i<=tot;i++)add(tr[i].fail,i);
idx=0,dfs(1);
build(1,1,tot);
int ans=0;
for(int i=1;i<=n;i++)
{
int tmp=0,po=1;
for(int j=pos[i-1];j<pos[i];j++)
{
po=tr[po].son[s[j]-'a'];
tmp=max(tmp,query(1,1,tot,in[po]));
}
tmp+=w[i];
modify(1,1,tot,in[po],out[po],tmp);
ans=max(ans,tmp);
}
printf("Case #%d: %d\n",C,ans);
}
}