状压dp——洛谷P3112 [USACO14DEC]后卫马克Guard Mark

https://daniu.luogu.org/problem/show?pid=3112
这种dp第二次遇到了,记录一下
我们看n只有20
那么n的所有状态就是只有1000000多
我们考虑对于每一个状态记录这个状态的总高度和当前最大承受力;
是不是可以通过枚举这个状态的每一个子状态得到;
比如
11
可以通过枚举
10
01
得到
那么就直接dp,用了很多位运算技巧,包括lowbit

#include<bits/stdc++.h>
#define Ll long long
using namespace std;
const Ll N=21;
Ll a[N],b[N],c[N],f[(1<<20)],sum[(1<<20)],p[(1<<20)+5];
Ll n,m,ans=-1e18;
int main()
{
    scanf("%lld%lld",&n,&m);
    for(Ll i=1;i<=n;i++)scanf("%lld%lld%lld",&c[i],&b[i],&a[i]);
    f[0]=1e18;
    for(Ll i=1;i<=n;i++)p[(1<<(i-1))]=i;
    for(Ll k=1;k<=(1<<n)-1;k++){
        Ll kk=k;f[k]=-1e18;
        while(kk){
            Ll t=kk&-kk,v=k^t;kk-=t;t=p[t];
            sum[k]+=c[t];
            if(f[v]>=b[t])f[k]=max(f[k],min(f[v]-b[t],a[t]));
        }
        if(sum[k]>=m)ans=max(ans,f[k]);
    }
    if(ans==-1e18)printf("Mark is too tall");else printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值