fastle
垆边人似月 皓腕凝霜雪
/*
用 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;
}

posted on 2019-04-21 21:11  fastle  阅读(150)  评论(0编辑  收藏  举报