构造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; }