zoukankan      html  css  js  c++  java
  • [luogu 3957]跳房子

    题目链接

    50分做法

    挺显然的一个做法,因为金币量是单调的(如果你花i枚金币可以得到最优解,i+1枚也一定可以),所以可以二分答案

    然后对于二分出来的每个答案,都做一遍dp,效率$O(n^2logn)$

    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 500100
    inline int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        return x*f;
    }
    int n,d,k,a[N],s[N],dp[N];
    int max(int x,int y){return x>y?x:y;}
    bool check(int g){
        memset(dp,128,sizeof(dp));
        int t1=(d-g)?d-g:1,t2=d+g,mx=0;
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<i;j++){
                if(a[i]-a[j]>=t1&&a[i]-a[j]<=t2)
                    dp[i]=max(dp[i],dp[j]+s[i]);
            }
        }
        for(int i=1;i<=n;i++)mx=max(dp[i],mx);
        if(mx>=k)return 1;
        return 0;
    }
    int main(){
        n=read();d=read();k=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),s[i]=read();
        int ans=0,l=0,r=10000000;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid))r=mid-1,ans=mid;
            else l=mid+1;
        }
        if(ans)printf("%d
    ",ans);
        else puts("-1");
        return 0;
    }
    50分做法

    100分做法

    考虑怎么让效率降下来

    50分的思路没问题,尝试一下能不能让每次dp的效率降下来

    观察到答案其实也是单调的,dp[i]的答案是从前面i-d-g个数转移过来的,所以可以使用单调队列优化

    总复杂度就变成$O(nlogn)$,能过100分的数据了

    #include <cstdio>
    #include <cstring>
    #define ll long long
    inline ll read(){
        ll x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    #define inf (1<<30)
    ll n,d,k,a[500010],s[500010];
    ll dp[500010];
    ll q[10000000];
    ll max(ll x,ll y){return x>y?x:y;}
    bool check(ll g){
        ll l=1,r=0,p=0,t1=max(d-g,1),t2=d+g;
        q[1]=0;
        for(int i=1;i<=n;i++){
            dp[i]=-inf;
            while(a[i]-a[p]>=t1&&p<i){
                while(l<=r&&dp[p]>=dp[q[r]])r--;
                q[++r]=p++;
            }
            while(a[i]-a[q[l]]>t2&&l<=r)l++;
            if(l>r||dp[q[l]]==-inf)continue;
            dp[i]=dp[q[l]]+s[i];
            if(dp[i]>=k)return 1;
        }
        return 0;
    }
    int main(){
        n=read(),d=read(),k=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),s[i]=read();
        a[0]=0,s[0]=0;
        ll l=0,r=1000000000,ans=-1;
        while(l<=r){
            ll mid=(l+r)>>1;
            if(check(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    100分做法
  • 相关阅读:
    解决CSS图片底部3像素问题总结
    常用伪元素及content属性值的使用
    javascript中用正则表达式判断是否为汉字及常用的判断
    javascript 正则表达式
    js常用事件
    js动态获取select选中的option
    innerHTML innerText与outerHTML间的区别
    vue的生命周期(又称钩子函数)----以及vue1.0版本与vue2.0版本生命周期的不同
    JavaScript实现表单验证_02
    JavaScript数组实现图片轮播
  • 原文地址:https://www.cnblogs.com/henry-1202/p/9399618.html
Copyright © 2011-2022 走看看