This commit is contained in:
2023-12-23 22:23:48 +08:00
commit 43ced8bd2a
58 changed files with 5702 additions and 0 deletions

116
ACMOJ-2032.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int kMaxN = 2000;
const double kEps = 1e-6;
const double kInf = 1e100;
int n, m;
char T[kMaxN], S[kMaxN];
int fail[kMaxN], trans[kMaxN][10], tot[kMaxN], node_cnt = 0;
double val[kMaxN];
void AddString(const char *s, double V) {
int p = 0;
while (*s) {
if (trans[p][*s - '0'] == 0) trans[p][*s - '0'] = ++node_cnt;
p = trans[p][*s - '0'];
s++;
}
tot[p]++;
val[p] += V;
}
void BuildAutomaton() {
int L = 0, R = 0;
int *Q = new int[kMaxN + 10]();
fail[0] = -1;
while (L <= R) {
int u = Q[L++];
for (int i = 0; i < 10; i++) {
if (trans[u][i] != 0) {
int v = fail[u];
while (v != -1 && trans[v][i] == 0) v = fail[v];
// 反复沿着失配边跳转
if (v != -1) fail[trans[u][i]] = trans[v][i];
// 子节点的内容在父节点就处理好
Q[++R] = trans[u][i];
} else if (fail[u] != -1)
trans[u][i] = trans[fail[u]][i];
// 其余情况置0回到初始状态
}
}
for (int i = 1; i <= R; i++) {
tot[Q[i]] += tot[fail[Q[i]]];
val[Q[i]] += val[fail[Q[i]]];
// 叠加,从贪心匹配变成匹配所有
}
delete[] Q;
}
double dp[kMaxN][kMaxN];
int pre_node[kMaxN][kMaxN];
char pre_char[kMaxN][kMaxN];
char last_ans[kMaxN];
double calc(double v_guess) {
for (int i = 0; i <= node_cnt; i++) val[i] -= tot[i] * v_guess;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= node_cnt; j++) dp[i][j] = -kInf;
dp[0][0] = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j <= node_cnt; j++) {
if (dp[i][j] == -kInf) continue;
if (T[i] != '.') {
int v = trans[j][T[i] - '0'];
if (dp[i][j] + val[v] > dp[i + 1][v]) {
dp[i + 1][v] = dp[i][j] + val[v];
pre_node[i + 1][v] = j;
pre_char[i + 1][v] = T[i];
}
} else {
for (int k = 0; k < 10; k++) {
int v = trans[j][k];
if (dp[i][j] + val[v] > dp[i + 1][v]) {
dp[i + 1][v] = dp[i][j] + val[v];
pre_node[i + 1][v] = j;
pre_char[i + 1][v] = '0' + k;
}
}
}
}
for (int i = 0; i <= node_cnt; i++) val[i] += tot[i] * v_guess;
int res_pos = 0;
for (int i = 1; i <= node_cnt; i++)
if (dp[n][i] > dp[n][res_pos]) res_pos = i;
for (int str_p = n, node_p = res_pos; str_p >= 1; str_p--) {
last_ans[str_p - 1] = pre_char[str_p][node_p];
node_p = pre_node[str_p][node_p];
}
last_ans[n] = 0;
return dp[n][res_pos];
}
int main() {
#ifdef local
freopen("pro.in", "r", stdin);
#endif
scanf("%d%d", &n, &m);
scanf("%s", T);
for (int i = 0; i < m; i++) {
int V;
scanf("%s%d", S, &V);
AddString(S, log(V));
}
BuildAutomaton();
double L = 0, R = log(1e9), M, res = 0;
while (R - L > kEps) {
M = (L + R) / 2;
if (calc(M) > 0) {
res = M;
L = M;
} else
R = M;
}
calc(res);
puts(last_ans);
return 0;
}