[BJOI2019]奧術神杖
阿新 • • 發佈:2019-04-21
scan tran con ostream algo har cos mes i++
/* 用 log去掉次方然後變成裸的01分數規劃問題 具體來說是要給每個trans賦值, 然後跑取max轉移吧 */ #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #include<cmath> #define ll long long #define M 1520 #define mmp make_pair using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } char s[M], tmp[M]; double f[M][M]; int n, m, pre[M][M], note[M], as[M][M]; struct AC { #define ch son int fail[M], son[M][10], end[M], cnt, fa[M], biao[M]; double sum[M], trans[M], v[M], cost[M]; void insert(double x) { int now = 0, len = strlen(tmp + 1); for(int i = 1; i <= len; i++) { if(ch[now][tmp[i] - '0'] == 0) ch[now][tmp[i] - '0'] = ++cnt, fa[cnt] = now, biao[cnt] = tmp[i] - '0'; now = ch[now][tmp[i] - '0']; } v[now] += x, end[now]++; } void getfail() { queue<int> q; for(int i = 0; i < 10; i++) if(son[0][i] != 0) fail[son[0][i]] = 0, q.push(son[0][i]), trans[son[0][i]] = v[son[0][i]], sum[son[0][i]] = end[son[0][i]]; while(!q.empty()) { int now = q.front(); q.pop(); for(int i = 0; i < 10; i++) { if(son[now][i] != 0) { fail[son[now][i]] = son[fail[now]][i]; trans[son[now][i]] += trans[son[fail[now]][i]]; sum[son[now][i]] += sum[son[fail[now]][i]]; if(end[son[now][i]]) trans[son[now][i]] += v[son[now][i]], sum[son[now][i]] += end[son[now][i]]; q.push(son[now][i]); } else son[now][i] = son[fail[now]][i]; } } // for(int i = 0; i < 10; i++) if(ch[0][i] == 0) biao[0] = i; } } ac; const double inf = pow(2, 70); void cl() { for(int i = 0; i <= n; i++) for(int j = 0; j <= ac.cnt; j++) f[i][j] = -inf;//, pre[i][j] = 0, as[i][j] = 0; } void dp() { f[0][0] = 0; for(int i = 1; i <= n; i++) { if(s[i] == '.') { for(int j = 0; j <= ac.cnt; j++) { for(int k = 0; k < 10; k++) { if(f[i][ac.son[j][k]] < f[i - 1][j] + ac.cost[ac.son[j][k]]) f[i][ac.son[j][k]] = f[i - 1][j] + ac.cost[ac.son[j][k]], pre[i][ac.son[j][k]] = j, as[i][ac.son[j][k]] = k; } } } else { int k = s[i] - '0'; for(int j = 0; j <= ac.cnt; j++) { if(f[i][ac.son[j][k]] < f[i - 1][j] + ac.cost[ac.son[j][k]]) f[i][ac.son[j][k]] = f[i - 1][j] + ac.cost[ac.son[j][k]], pre[i][ac.son[j][k]] = j, as[i][ac.son[j][k]] = k; } } } } bool check(double x) { for(int i = 1; i <= ac.cnt; i++) ac.cost[i] = ac.trans[i] - x * ac.sum[i]; cl(); dp(); for(int i = 0; i <= ac.cnt; i++) { if(f[n][i] > 0) { int now = i; for(int j = n; j >= 1; j--) { note[j] = as[j][now]; now = pre[j][now]; } return true; } } return false; } void getans() { double l = 0, r = 1.0 * 1e8; int up; if(n <= 501) up = 120; else up = 42; for(int j = 1; j <= up; j++) { double mid = (l + r) / 2; if(check(mid)) l = mid; else r = mid; } // printf("%.10lf\n", exp(l)); } int main() { n = read(), m = read(); scanf("%s", s + 1); for(int i = 1; i <= m; i++) { scanf("%s", tmp + 1); double v = read(); v = log(v); ac.insert(v); } for(int i = 1; i <= n; i++) note[i] = s[i] - '0'; ac.getfail(); getans(); for(int i = 1; i <= n; i++) cout << note[i]; cout << "\n"; return 0; }
[BJOI2019]奧術神杖