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<<" "; }else{ cout<<" "; } } }; 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; }