zoukankan      html  css  js  c++  java
  • 【NOIP2017普及组T4】跳房子-二分答案+DP单调队列优化

    测试地址:跳房子
    做法:本题需要用到二分答案+DP单调队列优化。
    首先我们发现答案显然具有单调性,于是二分答案,问题转化为判定性问题,即判定跳跃距离在dg~d+g之间时所能拿到的最大分数是不是k。这个我们显然想到用DP处理,令f(i)为走到第i个格子时所能拿到的最大分数,显然有状态转移方程:
    f(i)=max(f(j))(xidgxjxid+g)+si
    注意到满足条件的j的区间是单调右移的,于是用单调队列维护即可。时间复杂度为O(nlog109)
    傻逼的地方:细节错贼鸡儿多,inf还要开够大才行,哇……
    话说NOIP普及组考这么难真的好么……
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,d,x[500010];
    int q[500010],h,t;
    ll val[500010],f[500010],k,inf;
    
    bool check(int g)
    {
        f[0]=0;
        q[h=t=0]=0;
        int r=1;
        for(int i=1;i<=n;i++)
        {
            while(r<=n&&x[r]<=min(x[i]-1,x[i]-d+g))
            {
                while(h<=t&&f[q[t]]<=f[r]) t--;
                q[++t]=r;r++;
            }
            while(h<=t&&x[q[h]]<x[i]-d-g) h++;
            if (h<=t&&q[h]<=x[i]-d+g) f[i]=f[q[h]]+val[i];
            else f[i]=-inf;
            if (f[i]>=k) return 1;
        }
        return 0;
    }
    
    int main()
    {
        inf=1000000000;
        inf*=inf;
    
        scanf("%d%d%lld",&n,&d,&k);
        x[0]=val[0]=0;
        for(int i=1;i<=n;i++)
            scanf("%d%lld",&x[i],&val[i]);
    
        int l=0,r=1000000000;
        if (!check(1000000000)) {printf("-1");return 0;}
        while(l<r)
        {
            int mid=(l+r)>>1;
            if (check(mid)) r=mid;
            else l=mid+1;
        }
        printf("%d",l);
    
        return 0;
    }
  • 相关阅读:
    《人月神话》阅读笔记3
    第十五周总结
    《人月神话》阅读笔记2
    对正在使用的输入法评价
    课堂练习(找水王问题)
    第二阶段冲刺第十天
    第二阶段冲刺第九天
    第二阶段冲刺第八天
    第二阶段冲刺第七天
    openwrt U盘启动
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793543.html
Copyright © 2011-2022 走看看