【NOIP2013模拟11.7B组】道路覆盖(cover)

来源:互联网 发布:进入淘宝 编辑:程序博客网 时间:2024/06/05 19:54

题目网址

https://jzoj.net/senior/#contest/show/2037/1
//每次都写这个,但是我知道有些人进不去~sorry

小结

30%
——这个其实可以拿90分,听别人说的,我没有打过,你想打表过也可以~~
100%
——这个就是技术活了,我都理解了半天~(但我相信你会比我更加聪明!!因为我是个小蒟蒻~
首先,我们发现题目是最小的最大值,那么我们知道,这是一个非常典型的二分标志。那就说明——我们要用二分对,你很聪明,我知道你想到了),二分一个答案,然后就变成判定问题了,你一定会想到用递归去判定对吧,(噢不对,你是大神)算了,不管你知不知道,我还是讲一下,既然可以用递归判定,那就一定可以用dp判断对吧,现在我们就来看一下怎么用dp来判断~(这将会是一个有趣的旅行
好了,首先我们设f[i,s]表示到第i坨泥土的时候,前面k-1个的状态为s的情况(0表示不在这里放泥土,1表示我们从这里开始放泥土,放k坨)
我们设一个num来表示前面每一个放泥土时能够放到它的层泥土高度的和,(好好理解一下这句话)。
这里写图片描述
这就有两种情况,选和不选。
①选
那我们的num+h[i+1]>=mid
所以 f[i+1,下一个的状态]=min(f[i,s]+c[i+1]);
②不选
那我们的num+h[i+1]+e[i+1]>=mid
所以 f[i+1,下一个的状态]=min(f[i,s]);
然后,就过啦
看看代码:

    var        n,m,k,i,j,l,r,mid,sum,ma:longint;        f:array[0..100,0..2047]of longint;        c,e,h:array[0..100]of longint;function min(a,b:longint):longint;begin        if a>b then exit(b);        exit(a);end;function pd(mid:longint):boolean;var        i,j,s,s1,num,kk:longint;begin        fillchar(f,sizeof(f),127);        f[0,0]:=0;        for i:=0 to n-1 do        begin                for s:=0 to 1 shl k-1 do                begin                        num:=0;                        for j:=1 to k-1 do                        begin                                kk:=1 shl j;                                if s and kk>0 then                                        num:=num+e[i-(k-j-1)];                        end;                        if num+h[i+1]>=mid then                        begin                                s1:=s shr 1;                                f[i+1,s1]:=min(f[i+1,s1],f[i,s]);                        end;                        if num+h[i+1]+e[i+1]>=mid then                        begin                                s1:=(s shr 1)or(1 shl (k-1));                                f[i+1,s1]:=min(f[i+1,s1],f[i,s]+c[i+1]);                        end;                end;        end;        for i:=0 to 1 shl k-1 do                if f[n,i]<=m then exit(true);        exit(false);end;begin        assign(input,'cover.in');reset(input);        assign(output,'cover.out');rewrite(output);        readln(n,m,k);        for i:=1 to n do        begin                readln(h[i],e[i],c[i]);                sum:=sum+e[i];                if h[i]>ma then ma:=h[i];        end;        l:=1;        r:=sum+ma;        repeat                mid:=(l+r) div 2;                if pd(mid) then                        l:=mid+1                else                        r:=mid;        until l>=r;        writeln(l-1);        close(input);        close(output);end.

有没有发现,dp原来可以这么屌!!膜拜膜拜

阅读全文
0 0
原创粉丝点击