zoukankan      html  css  js  c++  java
  • [状压DP][二分]JZOJ 3521 道路覆盖

    Description

    ar把一段凹凸不平的路分成了高度不同的N段,并用H[i]表示第i段高度。现在Tar一共有n种泥土可用,它们都能覆盖给定的连续的k个部分。

    对于第i种泥土,它的价格为C[i],可以使得区间[i,min(n,i+k-1)] 的路段的高度增加E[i]。

    Tar要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:

    (1)每种泥土只能使用一次。

    (2)泥土使用成本必须小于等于M。

    请求出这个最低的高度最高是多少。
     

    Input

    第一行为如上文所示的三个正整数:N,M,K。

    接下来N行,每行3个如上文所示的正整数H[i],E[i],C[i]。

    Output

    输出有且只有一个数字,为最底部分的高度的最大值
     

    Sample Input

    4 20 1
    1 3 5
    1 7 3
    4 6 9
    3 5 13

    Sample Output

    3
     

    Data Constraint

    对于30%的数据:N≤20。

    对于100%的数据:1≤K≤11,1≤N≤100,0≤M,H[i],E[i],C[i]≤1000000。

    分析

    首先看数据范围,k那么小差不多就是状态压缩了

    最小值最大,显然二分

    我们二分最小高度,DP判断

    (然鹅比赛的时候蠢到没有想到第i位由前k位影响?)

    在display_lzy大爷机(you)缘(yi)巧(gao)合(zhi)之下,想到了上面括号里的内容

    设f[i][s]为前i段和前k种泥土的状态为s时满足最小值也大于等于二分值的最小代价

    如何维护高度?

    设h[i][s]为从第i中往前数k种泥土的状态为s时的能增加的高度,然后如果当前位高度加上这个也小于二分值的话就不合法,f[i][s]=Inf

    然后显然只能从s>>1和s>>1 + 1<<k-1转移过来

    最后找f[n][s]中有没有小于等于m的就行了 

    #include <iostream>
    #include <cstdio>
    #include <memory.h>
    using namespace std;
    const int N=110;
    int n,m,k;
    int h[N],e[N],c[N],mh=2147483647,sh,sumh,mxbit;
    int f[N][1<<12],h1[N][1<<12];
    
    bool Solve(int height) {
        memset(f,0x7f,sizeof f);
        memset(h1,-0x7f,sizeof h1);
        f[0][0]=h1[0][0]=0;
        for (int i=1;i<=n;i++)
            for (int j=0;j<=mxbit;j++) {
                int from1=j>>1,from2=(j>>1)+(1<<k-1);
                f[i][j]=min(f[i-1][from1],f[i-1][from2])+j%2*c[i];
                h1[i][j]=max(h1[i-1][from1]+j%2*e[i],h1[i][j]);
                if (h1[i][j]+h[i]<height) f[i][j]=0x7f7f7f7f;
            }
        for (int i=0;i<=mxbit;i++)
            if (f[n][i]<=m) return 1;
        return 0;
    }
    
    int main() {
        freopen("cover.in","r",stdin);
        freopen("cover.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for (int i=1;i<=n;i++)
            scanf("%d%d%d",&h[i],&e[i],&c[i]),mh=min(mh,h[i]),sh=max(sh,h[i]),sumh+=c[i];
        sh+=sumh;mxbit=(1<<k)-1;
        int l=mh,r=sh,mid,ans=0;
        while (l<=r) {
            mid=l+r>>1;
            if (Solve(mid)) ans=max(ans,mid),l=mid+1;
            else r=mid-1;
        }
        printf("%d",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    批量备份mysql数据库(shell编程)
    批量检查多个网址是否正常(shell编程)
    就linux三剑客简单归纳
    sql语句浅谈以及mysql遇到的问题解决见解
    linux shell每天一阅 -- 安装nginx以及apache
    Linux文件系统检查错误
    Linux账号管理和ACL
    简书博客
    Block内的强引用
    一次没有意义的优化
  • 原文地址:https://www.cnblogs.com/mastervan/p/9826655.html
Copyright © 2011-2022 走看看