zoukankan      html  css  js  c++  java
  • [BJOI2019]奥术神杖

    /*
    用 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
    ", 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 << "
    ";
    	return 0;
    }
    
    
  • 相关阅读:
    LeetCode449. 序列化和反序列化二叉搜索树
    LeetCode448. 找到所有数组中消失的数字
    一行代码如何隐藏 Linux 进程?
    C语言这么厉害,它自身又是用什么语言写的?
    了解C语言,是否代表了解C ++的一半?
    C语言小白那些不知道的事儿
    6 条 Git 实用技巧
    干货来袭,收藏方便找到该网站
    零基础小白如何入门Shell,快来看看(收藏)这篇大总结!!
    Java用于嵌入式系统的优点和局限
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/10746965.html
Copyright © 2011-2022 走看看