离线建树,然后按顺序把值插入,每插入一个值的时候就按着fail算出该节点的最优解。
一个优化,那些值小于0的节点直接去掉,这个代码不能保证ac,因为这个做法上界很高,但是这题貌似数据随机生成,偶尔能够ac。。。
这个题目正解的话,是要加上线段树来优化这个做法的,因为按照fail指针可以构造出一棵树,算最优解的过程就变成不断更新节点的所有孩子值,求节点的最大值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn=3e5+9,N=26,root=0,maxm=2e4+9;
int cas=0;
int lon;
struct
{
int next[N],tmp,fail;
}trie[290000];
void clr(int t)
{
for(int i=0;i<N;i++) trie[t].next[i]=0;
trie[t].tmp=trie[t].fail=0;
}
void trieini()
{
clr(0);
lon=0;
}
void insert(char s[])
{
int t=root;
int n=strlen(s+1);
for(int i=1;i<=n;i++)
{
if(trie[t].next[s[i]-'a']==0)
{
trie[t].next[s[i]-'a']=++lon;
clr(lon);
}
t=trie[t].next[s[i]-'a'];
}
}
void getfail()
{
queue <int> q;
q.push(root);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0;i<N;i++)
if(trie[t].next[i])
{
int u=trie[t].next[i];
int tmp=trie[t].fail;
while(tmp!=root&&trie[tmp].next[i]==0)
tmp=trie[tmp].fail;
trie[u].fail=trie[tmp].next[i];
if(t==root) trie[u].fail=root;
q.push(u);
}
}
}
int a[maxm];
char s[maxn+21111];
void solve(int top,int n)
{
int now=1;
for(int i=1,t=root,ret=0,u;now<=n;i++)
{
if(s[i]=='#')
{
trie[t].tmp=ret+a[now];
now++;
ret=0;
t=root;
continue;
}
t=trie[t].next[s[i]-'a'];
u=t;
while(u!=root)
{
ret=max(ret,trie[u].tmp);
u=trie[u].fail;
}
}
int ans=0;
for(int i=1;i<=lon;i++)
ans=max(ans,trie[i].tmp);
printf("Case #%d: %d\n",++cas,ans);
}
int main()
{
// freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
trieini();
int n,top=0,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s %d",s+1+top,&a[i]);
if(a[i]<0)
{
i--;
n--;
continue;
}
insert(s+top);
m=strlen(s+1+top);
top+=m;
s[++top]='#';
}
getfail();
solve(top,n);
}
return 0;
}