题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值。求字符串的最大价值。每个单词的价值就是单价*出现次数。单词可以重叠。如果不止一个答案,选择字典序最小的。
题解:AC自动机+dp。dp[i][j]表示在字符串长度i,在自动机的第j个状态。因为要字典序最小,所以转移时要保持字典序最小。
想了各种转移姿势 最后还是查了题解 发现可以直接记录前缀转移……
#include <bits/stdc++.h> using namespace std; const int N = 1500; const int A = 26; const int M = 105; struct ACAutomata { int next[N][A], fail[N], end[N]; int root, L; int alp[N]; int idx(char ch) { return ch - ‘a‘; } int newNode() { for (int i = 0; i < A; ++i) next[L][i] = -1; end[L] = 0; return L++; } void init() { L = 0; root = newNode(); } void insert(char buf[], int v) { int len = strlen(buf); int now = root; for (int i = 0; i < len; ++i) { int ch = idx(buf[i]); if (next[now][ch] == -1) { next[now][ch] = newNode(); alp[L-1] = ch; } now = next[now][ch]; } end[now] += v; } void build() { queue<int> Q; for (int i = 0; i < A; ++i) { if (next[root][i] == -1) { next[root][i] = root; } else { fail[ next[root][i] ] = root; Q.push( next[root][i] ); } } while (Q.size()) { int now = Q.front(); Q.pop(); end[now] += end[ fail[now] ]; //注意这里! for (int i = 0; i < A; ++i) { if (next[now][i] == -1) { next[now][i] = next[ fail[now] ][i]; } else { fail[ next[now][i] ] = next[ fail[now] ][i]; Q.push(next[now][i]); } } } } } ac; char buf[M][20]; int v[M]; int dp[M][N]; string ans[M][N]; int main() { int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d%d", &n, &m); ac.init(); for (int i = 0; i < m; ++i) scanf("%s", buf[i]); for (int i = 0; i < m; ++i) scanf("%d", &v[i]); for (int i = 0; i < m; ++i) ac.insert(buf[i], v[i]); ac.build(); memset(dp, -1, sizeof dp); dp[0][0] = 0; ans[0][0] = ""; for (int i = 0; i < n; ++i) for (int j = 0; j < ac.L; ++j) if (dp[i][j] >= 0) for (int k = 0; k < 26; ++k) { int nt = ac.next[j][k]; if (dp[i][j]+ac.end[nt] > dp[i+1][nt] || dp[i][j]+ac.end[nt] == dp[i+1][nt] && ans[i][j]+char(k+‘a‘) < ans[i+1][nt]) { dp[i+1][nt] = dp[i][j] + ac.end[nt]; ans[i+1][nt] = ans[i][j] + char(k+‘a‘); } } string res; int maxv = 0; for (int i = 0; i <= n; ++i) for (int j = 0; j < ac.L; ++j) if (maxv < dp[i][j]) { maxv = dp[i][j]; res = ans[i][j]; } for (int i = 0; i <= n; ++i) for (int j = 0; j < ac.L; ++j) if (maxv == dp[i][j]) if (ans[i][j].size() < res.size() || ans[i][j].size() == res.size() && ans[i][j] < res) res = ans[i][j]; cout << res << endl; } return 0; }
时间: 2024-10-25 13:08:10