Files
SH-Quizzes/ACMOJ-2032.cpp
2023-12-23 22:23:48 +08:00

116 lines
3.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}