zoukankan      html  css  js  c++  java
  • 题解 P3957 【跳房子】

    题目链接

    Solution 跳房子

    题目大意:给定(n)个格子离原点距离以及权值,初始单次移动距离只能为(d),你可以花费(g)枚金币使得单次移动距离变为([max(d-g,1),d+g])内任意整数,问获得权值至少为(k)最少需要花费多少枚金币

    单调队列


    分析:显而易见答案具有单调性,因为花费金币越多机器人越灵活,花费金币少的可行决策是花费金币多的可行决策的子集

    我们可以二分一个答案(ans),如果(O(n^2))(dp)的话可以得到(50)

    对于任意一个位置,它能转移的位置都在一段区间内,由于每个格子位置单调递增,可行转移状态集合类似于滑动窗口,可以用单调队列来维护,做到(O(n)dp)

    注意初始值

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    const int maxn = 5e5 + 100;
    typedef long long ll;
    struct Node{
    	int pos,val;
    }val[maxn];
    int q[maxn],head,tail,n,d,k,l = 0,r = 1e9,ans = -1;
    ll f[maxn];
    inline bool check(int g){
    	int l = max(d - g,1),r = d + g,pos = 0,head = 1,tail = 0;
    	for(int i = 1;i <= n;i++)f[i] = -1e13;
    	for(int i = 1;i <= n;i++){
    		while(pos < i && val[pos].pos <= val[i].pos - l){
    			while(head <= tail && f[q[tail]] <= f[pos])tail--;
    			q[++tail] = pos++;
    		}
    		while(head <= tail && val[q[head]].pos < val[i].pos - r)head++;
    		if(head <= tail)f[i] = f[q[head]] + val[i].val;
    	}
    	for(int i = 1;i <= n;i++)
    		if(f[i] >= k)return true;
    	return false;
    }
    int main(){
    	scanf("%d %d %d",&n,&d,&k);
    	for(int i = 1;i <= n;i++)
    		scanf("%d %d",&val[i].pos,&val[i].val);
    	while(l <= r){
    		int mid = (l + r) >> 1;
    		if(check(mid))ans = mid,r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    html中的块级元素、行内元素
    ptyhon_opencv 图像的基本操作
    正则表达式总结 2017.1.6
    HashMap 中的 entrySet()使用方法 2016.12.28
    (转)Redis持久化的几种方式
    负数与二进制换转方法
    (转)2019JAVA面试题附答案(长期更新)
    Java后端技术面试汇总(第一套)
    (转)Dubbo服务暴露过程源码分析
    Dubbo消费方服务调用过程源码分析
  • 原文地址:https://www.cnblogs.com/colazcy/p/11858600.html
Copyright © 2011-2022 走看看