116 lines
3.0 KiB
C++
116 lines
3.0 KiB
C++
#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;
|
||
} |