zoukankan      html  css  js  c++  java
  • 「LibreOJ NOIP Round #1」旅游路线

    这道题真的好棒啊.. 不愧是WA爷出的题啊


    题目大意

    有$n$个点$m$条有向边,在每个点可以花$p_i$的钱加油至$min(C,c_i)$,每经过一条边会耗费$1$的油量

    给出$T$个询问,每次询问从$s$出发,$q$块钱,走$d$的路程最多剩下多少钱


    我好菜啊..

    只能想到设$f_{i,q,c}$为走到$i$节点剩下$q$块钱还有$c$油量的最大路程来dp..

    但是没法摆脱油量的限制

    题解的做法很棒

    就是设$f_{i,q}$为走到$i$节点并且在这里加油还剩下$q$块钱的最大路程,然后枚举下一次加油的地方来dp

    那问题现在就转化为求从$i$到$j$不经过$min(C,c_i)$条边的最大路程

    然后发现这个东西可以倍增求就很棒了


    code

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #define LL long long
    using namespace std;
    const LL Maxn = 110;
    const LL Maxp = 100010;
    const LL lg = 17;
    const LL inf = (LL)1<<60;
    LL f[Maxn][Maxn*Maxn];
    LL g[lg][Maxn][Maxn];
    LL w[Maxn][Maxn];
    LL n, m, C, T;
    LL p[Maxn], c[Maxn];
    LL bit[Maxp];
    LL A[Maxn], B[Maxn];
    LL _max(LL x, LL y) { return x > y ? x : y; }
    LL _min(LL x, LL y) { return x < y ? x : y; }
    int main() {
    	LL i, j, k;
    	scanf("%lld%lld%lld%lld", &n, &m, &C, &T);
    	for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) g[0][i][j] = i == j ? 0 : -inf;
    	for(i = 1; i <= n; i++) scanf("%lld%lld", &p[i], &c[i]);
    	for(i = 1; i <= m; i++){
    		LL x, y, d;
    		scanf("%lld%lld%lld", &x, &y, &d);
    		g[0][x][y] = _max(g[0][x][y], d);
    	}
    	for(LL x = 1; x < lg; x++){
    		for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) g[x][i][j] = -inf;
    		for(k = 1; k <= n; k++){
    			for(i = 1; i <= n; i++){
    				for(j = 1; j <= n; j++) g[x][i][j] = _max(g[x][i][j], g[x-1][i][k]+g[x-1][k][j]);
    			}
    		}
    	}
    	for(i = 2; i <= 100000; i++) bit[i] = bit[i>>1]+1;
    	for(i = 1; i <= n; i++){
    		for(j = 1; j <= n; j++) A[j] = i == j ? 0 : -inf;
    		LL u = _min(C, c[i]);
    		for(int x = 0; x < lg; x++){
    			if(u&(1<<x)){
    				for(j = 1; j <= n; j++){
    					B[j] = -inf;
    					for(k = 1; k <= n; k++){
    						B[j] = _max(B[j], A[k]+g[x][k][j]);
    					}
    				}
    				for(j = 1; j <= n; j++) A[j] = B[j];
    			}
    		}
    		for(j = 1; j <= n; j++) w[i][j] = A[j];
    	}
    	for(i = 0; i <= n*n; i++){
    		for(j = 1; j <= n; j++){
    			if(i < p[j]){ f[j][i] = 0; continue; }
    			f[j][i] = -inf;
    			for(k = 1; k <= n; k++) f[j][i] = _max(f[j][i], f[k][i-p[j]]+w[j][k]);
    		}
    	}
    	while(T--){
    		LL s, q, d;
    		scanf("%lld%lld%lld", &s, &q, &d);
    		if(f[s][q] < d){ printf("-1
    "); continue; }
    		LL L = 0, R = q, ret;
    		while(L <= R){
    			LL mid = L+R>>1;
    			if(f[s][mid] >= d){ ret = mid; R = mid-1; }
    			else L = mid+1;
    		}
    		printf("%lld
    ", q-ret);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    docker6 管理工具
    docker1 初识docker
    libsvm处理多分类的问题
    selenium webdriver 的三种等待方式
    文本深度表示模型Word2Vec
    机器学习中训练集、验证集、测试集的定义和作用
    机器学习中防止过拟合的处理方法
    用Python读取大文件
    进化世界
    EDS(实例)
  • 原文地址:https://www.cnblogs.com/darklove/p/7809272.html
Copyright © 2011-2022 走看看