• 洛谷 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

  • 相关阅读:
    输入输出那些事
    NYOJ 20
    NYOJ 283
    HDU 1285
    HDU 2639(第K大背包)
    HDU 4288
    对Visual Studio C++ hash_map严谨一点的测试转载
    vc6,vc.net,vc7,vc8,vc9,c,c++,c#的区别与联系
    我在南大的七年刘末鹏
    慎用Visual Studio C++默认的hash_map转载
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15200933.html
Copyright © 2020-2023  润新知