构造Trie树..通过Trie树构造AC自动机..再通过AC自动机构造Trie图...
本题DP的状态为dp[k][p].w 代表当字符串长度为k时..以头节点到p点为后缀的串所能得到的最大权值...同时用dp[k][p].s来存这个k长度的串..状态转移方向为Trie图中有向边的方向..显然k长度的状态只于k-1的状态有关..所以可以用滚动数组来存储dp状态..
值得注意的是我以前做AC自动机DP时..在更新时没有考虑过用来更新的点在上一层是否有过更新...而本题是一定要考虑的..只有上一层更新过的点才能在当前层更新其沿有向边能到达的点...
我有一个错误查了很久才解决..以后为了不出错..类似的DP在本层全部点更新完毕后,再来扫描所有点的权值更新ans吧...
贡献两组测试时自己出的数据:
TEST 1: 1 4 2 aa bb 3 3 ans= aaaa TEST 2: 1 49 3 loveufoever ever al 12 7 3 ans= aloveufoeveraloveufoeveraloveufoeveraloveufoever
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node1
{
int son[26],fail,w;
}point[1200];
struct node2
{
string s;
int w;
}dp[2][1200];
int T,m,n,w[102],i,j,num,h,k,x,len,t,ans;
char s[15];
string str,ans_str;
queue<int> myqueue;
bool used[1200];
bool judge(string a,string b)
{
int la=a.length(),lb=b.length();
if (la!=lb) return la>lb;
return a>b;
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
while (!myqueue.empty()) myqueue.pop();
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
memset(point,0,sizeof(point));
num=0;
for (i=1;i<=m;i++)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (j=0;j<len;j++)
{
if (!point[h].son[s[j]-'a'])
point[h].son[s[j]-'a']=++num;
h=point[h].son[s[j]-'a'];
}
point[h].w=i;
}
memset(w,0,sizeof(w));
for (i=1;i<=m;i++) scanf("%d",&w[i]);
for (i=0;i<26;i++)
if (point[0].son[i]) myqueue.push(point[0].son[i]);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
point[h].w=w[point[h].w]+point[point[h].fail].w;
for (i=0;i<26;i++)
{
k=point[h].fail;
while (k && !point[k].son[i]) k=point[k].fail;
point[point[h].son[i]].fail=point[k].son[i];
if (point[h].son[i])
myqueue.push(point[h].son[i]);
else
point[h].son[i]=point[k].son[i];
}
}
k=0;
for (i=0;i<=num;i++)
{
dp[k][i].w=0;
dp[k][i].s="";
}
ans=0; ans_str="";
while (n--)
{
k=1-k;
for (i=0;i<=num;i++)
{
dp[k][i].w=0;
dp[k][i].s="";
}
memset(used,false,sizeof(used));
used[0]=true;
myqueue.push(0);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
for (i=0;i<26;i++)
{
x=point[h].son[i];
if (!used[x])
{
used[x]=true;
myqueue.push(x);
}
if (h && dp[1-k][h].s=="") continue;
if (dp[k][x].w>dp[1-k][h].w+point[x].w) continue;
str=dp[1-k][h].s+char('a'+i);
if (dp[k][x].w<dp[1-k][h].w+point[x].w ||
dp[k][x].s=="" || judge(dp[k][x].s,str))
{
dp[k][x].w=dp[1-k][h].w+point[x].w;
dp[k][x].s=str;
}
}
}
for (h=0;h<=num;h++)
if (dp[k][h].w>ans || dp[k][h].w==ans && judge(ans_str,dp[k][h].s))
{
ans=dp[k][h].w;
ans_str=dp[k][h].s;
}
}
// printf("%d\n",ans);
len=ans_str.length();
for (i=0;i<len;i++) printf("%c",ans_str[i]);
printf("\n");
}
return 0;
}