zoukankan      html  css  js  c++  java
  • 洛谷 P3957 [NOIP2017 普及组] 跳房子(二分,单调队列优化dp)

    传送门

    第一年noip的考试题哇,满满的回忆
    当年就因为这个题输出-1骗了5分拿了普及一等


    解题思路

    先二分答案,很显然答案满足单调性。
    然后就是一个从限定范围转移过来的线性dp,用单调队列维护一下即可。
    判断-1可以根据所有的正数加起来是否大于等于k。
    细节还是很多的:

    1. dp数组初始化为一个很小的负数,防止有些跳不到的点在出现在了单调队列里
    2. 从零点开始枚举,这样第一个点跳不到也没问题
    3. 当求某个点dp值时发现队列为空,说明没有点能跳到这个点,continue即可(注意不是return 0)
    4. 注意更新队列顺序:先更新back,再更新head,再求当前点的dp值
    5. 注意每求得一个dp,都需要判断一下是否满足条件(题意中说可以随时停下)

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    #include<deque>
    using namespace std;
    const int maxn=500005;
    const int maxx=1e9;
    int n,k,d,l,r=maxx,x[maxn],s[maxn];
    long long sum,dp[maxn];
    bool check(int mid){
    	deque<int> q; 
    	int ss=max(1,d-mid),t=min(maxx,d+mid),now=0;
    	memset(dp,-0x3f,sizeof(dp));
    	dp[0]=0;
    	for(int i=0;i<=n;i++){
    		while(now<i&&x[i]-x[now]>=ss){
    			while(!q.empty()&&dp[now]>dp[q.back()]) q.pop_back();
    			q.push_back(now);
    			now++;
    		}
    		while(!q.empty()&&x[i]-x[q.front()]>t) q.pop_front();
    		if(q.empty()) continue;
    		dp[i]=dp[q.front()]+s[i];
    		if(dp[i]>=k) return 1;
    	}
    	return 0;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>d>>k;
    	for(int i=1;i<=n;i++){
    		cin>>x[i]>>s[i];
    		if(s[i]>0) sum+=s[i];
    	}
    	if(sum<k){
    		cout<<"-1"<<endl;
    		return 0;
    	}
    	while(l<r){
    		int mid=(l+r)/2;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	cout<<l;
        return 0;
    }
    

    //NOIP2017普及组 t4

  • 相关阅读:
    内置对象
    js作用域对象与运用技巧
    js流程控制与函数
    JavaScript基础
    CSS3新增属性2
    CSS3新增
    前端实践
    浮动与定位
    页面布局
    表格表单视频音频
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15200933.html
Copyright © 2011-2022 走看看