jzoj[3521]. 【NOIP2013模拟11.7B组】道路覆盖(cover) (状压DP)

来源:互联网 发布:淘宝网小商品 编辑:程序博客网 时间:2024/06/05 09:55

Link

https://jzoj.net/senior/#main/show/3521

Problem

给定n个操作,总价值m,以及一个整数k,每个操作给定三个整数hi,ei,ci,分别表示:第i个数的大小,把i~i+k-1中的数加上hi,价值
保证选中数的价值和<=m,使得整个序列的最小数最大

Data constraint

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

Solution

一看到最小数最大,必须想到二分.

我们二分一个答案h,现在来判断是否可行;

有两种方法;

一、暴力递归+一堆剪枝

期望分数:80

二、状压Dp

这种对一个区间进行修改的操作,很明显是无后效性的,也很明显可以想到状压Dp;

状压DP就是通过枚举所有状态来Dp,当然这个状态不能过多,否则一无法表示,二无法储存;

那么我们看看这题为什么对于n<=100都可以状压;

因为k<=11……………………

很显然,我们对于一个i,只需保留其前k位就行了,然后枚举i+1位的状态选还是不选,转移即可.

具体的Fi,s状态表示前i个数中,选数的状态为S的最小价值.

枚举一个对应的i+1的状态p,很显然x=(s and ((1 shl (k-1))-1)) shl 1+p就是i+1位对应的状态.

var        f:array[0..100,0..4096] of longint;        h,e,c,w:array[-1000..1000] of longint;        n,m,k,i,l,r,mid,ans:longint;function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end;function pd(high:longint):boolean;var     i,j,p,q,x,t,sum,ans,pp:longint;begin        fillchar(f,sizeof(f),$7f);        f[0,0]:=0;        ans:=10000000;        for i:=0 to n-1 do                for j:=0 to (1 shl k)-1 do                begin                        if f[i,j]>m then continue;                        t:=j;                        w[0]:=0;                        while t>0 do                        begin                                inc(w[0]); w[w[0]]:=t mod 2;                                t:=t shr 1;                        end;                        sum:=0;                        if w[0]=k then pp:=w[0]-1 else pp:=w[0];                        for q:=pp downto 1 do                                inc(sum,e[i-q+1]*w[q]);                        for p:=0 to 1 do                        begin                                x:=(j and ((1 shl (k-1))-1)) shl 1+p;                                if (h[i+1]+sum+p*e[i+1]>=high) and (f[i,j]+c[i+1]*p<=m) then                                begin                                        f[i+1,x]:=min(f[i+1,x],f[i,j]+c[i+1]*p);                                        if (i=n-1) then ans:=min(ans,f[i+1,x]);                                end;                        end;                end;        if ans<10000000 then exit(true) else 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                readln(h[i],e[i],c[i]);        l:=1;        r:=10000000;        while l<=r do        begin                mid:=(l+r) shr 1;                if pd(mid) then                begin                        ans:=mid;                        l:=mid+1;                end                else                        r:=mid-1;        end;        writeln(ans);        close(input); close(output);end.
阅读全文
0 0
原创粉丝点击