一道AC自动机+DP,因为单词可能重复,所以记录结点信息的需要是以个vector,然后dp的时候需要递归的更新dp值,因为一个结点可能为多个单词的结尾。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
const int maxn=300010;
const int sigma=26;
int ch[maxn][sigma];
vector<int> val[maxn];
int sz;
void init()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));
val[0].clear();
}
int idx(char c){return c-'a';}
void insert(string s,int v)
{
int u=0,n=s.size();
for(int i=0;i<n;i++)
{
int c=idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz].clear();
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u].push_back(v);
}
int f[maxn],last[maxn];
void getfail()
{
queue<int> q;
f[0]=0;
for(int c=0;c<sigma;c++)
{
int u=ch[0][c];
if(u)
{
f[u]=0;
q.push(u);
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<sigma;c++)
{
int u=ch[r][c];
if(!u) continue;
q.push(u);
int v=f[r];
while(v && !ch[v][c]) v=f[v];
f[u]=ch[v][c];
last[u]=val[f[u]].size()>0?f[u]:last[f[u]];
}
}
}
int n;
string s[20010];
int dp[20010],v[20010];
void update(int i,int j)
{
if(val[j].size()>0)
{
for(int k=0;k<val[j].size();k++)
if(val[j][k]<i) dp[i]=max(dp[i],dp[val[j][k]]+v[i]);
update(i,last[j]);
}
}
int main()
{
//freopen("data","r",stdin);
int T,kase=1;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s[i];
scanf("%d",&v[i]);
insert(s[i],i);
}
getfail();
for(int i=1;i<=n;i++)
{
int len=s[i].size(),u=0;
dp[i]=v[i];
for(int j=0;j<len;j++)
{
u=ch[u][idx(s[i][j])];
//cout<<u<<" "<<val[u][0]<<endl;
if(val[u].size()>0) update(i,u);
else if(val[last[u]].size()>0) update(i,last[u]);
}
//cout<<dp[i]<<endl;
}
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
printf("Case #%d: %d\n",kase++,ans);
}
return 0;
}