dp[i][j]表示行走i步到达j的最大值,dps[i][j]表示对应的串
状态转移方程如下:
dp[i][chi[j][k]] = min(dp[i - 1][j] + sum[chi[j][k]])
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;
#define hash(x) x-'a';
const int N = 20000, CH = 26, INF = 0x3F3F3F3F;
int n, m;
struct Trie{
Trie *next[CH];
Trie *fail;
int id;
}tree[N];
string dps[60][2008];
string ans;
//dp[i][j]表示行走i步到达j的最大值,dps[i][j]表示对应的串
int dp[60][2008];
int chi[1008][CH];
int sum[1008];
//先选长度短的,再按字典序选
inline string min(string &a, string &b){
if(a.size() != b.size()){
return a.size() < b.size()? a :b;
}
return a < b? a :b;
}
class AC_Auto{
int size;
Trie *root;
int mx;
public:
AC_Auto(){
root = &tree[0];
size=0;
memset(&tree[0], 0, sizeof(Trie));
}
void insert(char *s, int si){
Trie *p = root;
for(int i = 0; s[i]; i++){
int c = hash(s[i]);
if(!p -> next[c]){
memset(&tree[++size], 0, sizeof(Trie));
p -> next[c] = &tree[size];
p -> next[c] ->id = size;
}
p = p -> next[c];
}
sum[p -> id] = si;
}
void build(){
queue<Trie *> q;
q.push(root);
root -> fail = NULL;
while(!q.empty()){
Trie *now = q.front();
q.pop();
if(now -> fail){
//累加求串包含的子串价值和
sum[now -> id] += sum[now -> fail -> id];
}
for(int i = 0; i < CH; i++){
Trie *son = now -> next[i];
Trie *tp = (now == root)? root: now -> fail->next[i];
if(son == NULL){
now -> next[i] = tp;
}else{
son -> fail = tp;
q.push(son);
}
son = now -> next[i];
chi[now -> id][i] = son->id;
}
}
}
void solve(){
mx = 0;
ans.clear();
for(int i = 0; i <= n; i++){
for(int j = 0; j <= size; j++){
dp[i][j] = -INF;
dps[i][j].clear();
}
}
dp[0][0] = 0;
//枚举步骤,再枚举节点,状态转移
for(int i = 1; i <= n; i++){
for(int j = 0; j <= size; j++){
if(dp[i - 1][j] < 0){
continue;
}
for(int k = 0; k < CH; k++){
if(dp[i][chi[j][k]] < dp[i - 1][j] + sum[chi[j][k]]){
dp[i][chi[j][k]] = dp[i - 1][j] + sum[chi[j][k]];
dps[i][chi[j][k]] = dps[i - 1][j] + (char)(k + 'a');
}else if(dp[i][chi[j][k]] == dp[i - 1][j] + sum[chi[j][k]]){
dps[i][chi[j][k]] = min(dps[i - 1][j] + (char)(k + 'a'), dps[i][chi[j][k]]);
}
if(mx < dp[i][chi[j][k]]){
mx = dp[i][chi[j][k]];
ans = dps[i][chi[j][k]];
}else if(mx == dp[i][chi[j][k]]){
ans = min(ans, dps[i][chi[j][k]]);
}
}
}
}
if(ans.size() > 0){
cout<<ans<<"\n";
}else{
cout<<"\n";
}
}
};
char str[1008][1008];
int main(){
int t;
cin>>t;
while(t--){
AC_Auto ac;
cin>>n>>m;
memset(sum, 0 , sizeof(sum));
for(int i = 0; i < m; i++){
scanf("%s", str[i]);
}
for(int i = 0; i < m ; i++){
int val;
scanf("%d", &val);
ac.insert(str[i], val);
}
ac.build();
ac.solve();
}
return 0;
}