[状压DP][二分]JZOJ 3521 道路覆盖
分析
首先看数据范围,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); }
在日渐沉没的世界里,我发现了你。