思路:
开个结构体,dp[i][j]记录从i号节点开始走j步能得到的最大的权值,以及走到最大权值的方案,还有答案,每次枚举能走到的所有点,更新答案,如果答案一样就选择字典序小的一个。也可以只记录走到该节点的父亲节点,这样每次答案一样时选字典小的就通过不断回退来确定。
#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <string>
#include <queue>
#define M 110
#define N 60
using namespace std;
int n, m, val[M];
char pat[M][15];
class DPNode
{
public:
int val;
string str;
};DPNode dp[M*11][N];
class Node
{
public:
int endCnt, next[30], fail, val;
Node() {}
void clr()
{
endCnt = 0;
memset(next, 0, sizeof next);
fail = 0;
val = -1;
}
};
Node node[M*11];
class Trie
{
public:
int root, cnt;
int newNode()
{
node[++cnt].clr();
return cnt;
}
void init()
{
cnt = 0;
root = newNode();
}
void ins(char pat[], int len, int val)
{
int p = root;
for(int i = 0; i < len; i++)
{
int cur = pat[i]-'a';
if(!node[p].next[cur])
node[p].next[cur] = newNode();
p = node[p].next[cur];
}
node[p].endCnt++;
node[p].val = val;
}
void build()
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int cur = q.front();
q.pop();
for(int i = 0; i < 26; i++)
{
int nxt = node[cur].next[i];
if(nxt)
{
int p = node[cur].fail;
for(; p && node[p].next[i] == 0; p = node[p].fail);
p = p ? node[p].next[i] : root;
node[nxt].fail = p;
q.push(nxt);
}
}
}
}
int cmp(string a, string b)
{
for(int i = a.length()-1; i >= 0; i--)
{
if(a[i] != b[i]) return a[i] < b[i];
}
return 0;
}
void solve()
{
for(int i = 1; i <= cnt; i++)
{
for(int j = 0; j <= n; j++)
{
dp[i][j].val = 0;
dp[i][j].str = "";
}
}
for(int i = 1; i <= cnt; i++)
{
if(node[i].endCnt > 0)
dp[i][0].val = node[i].val;
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= cnt; j++)
{
for(int k = 0; k < 26; k++)
{
int p;
if(node[j].next[k])
{
p = node[j].next[k];
}
else
{
p = node[j].fail;
for(; p && node[p].next[k] == 0; p = node[p].fail);
p = p ? node[p].next[k] : root;
}
if(dp[p][i-1].val > dp[j][i].val)
{
dp[j][i].val = dp[p][i-1].val;
dp[j][i].str = dp[p][i-1].str+(char)(k+'a');
}
else if(dp[p][i-1].val == dp[j][i].val)
{
string temp = dp[p][i-1].str+(char)(k+'a');
if(dp[j][i].str == "" || cmp(temp, dp[j][i].str))
{
dp[j][i].str = temp;
}
}
}
if(node[j].endCnt > 0)
dp[j][i].val += node[j].val;
}
}
int maxv = dp[root][n].val;
string ans = "";
for(int i = n; i >= 0; i--)
{
if(dp[root][i].val < maxv) break;
ans = dp[root][i].str;
}
int lenans = ans.length();
for(int i = 0; i < lenans/2; i++) swap(ans[i], ans[lenans-1-i]);
//cout << "val: " << dp[root][n].val << endl;;
cout << ans << endl;
}
};
Trie trie;
int main()
{
//freopen("C:\\Users\\zfh\\Desktop\\in.txt", "r", stdin);
int t; scanf("%d", &t);
while(t--)
{
trie.init();
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
scanf(" %s", pat[i]);
}
for(int i = 0; i < m; i++)
{
scanf("%d", &val[i]);
}
for(int i = 0; i < m; i++)
{
trie.ins(pat[i], strlen(pat[i]), val[i]);
}
trie.build();
trie.solve();
}
return 0;
}