Loading

P3092 [USACO13NOV]No Change G-状压dp

P3092 [USACO13NOV]No Change G

题意:有k(k≤16)个硬币顺序买n个物品,没有找零且每次只能使用一个硬币,求剩下的钱数的最大值。

\[dp[i{XOR}(1<<(j-1)]=max(upperbound(yuan+1,yuan+1+n,zhui[dp[i]]+zhi[j])-yuan-1) \]

由于没有找零且每次付款只能使用一个硬币(否则一次性付完的结果是更优的),需要从dp[i]开始转移,否则2^16暴力枚举所有情况即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int maxn=1e6+10;
int n,k;
int zhi[20],yuan[maxn],zhui[maxn],dp[maxn];
signed main(){
    cin>>k>>n;
    for(int i=1;i<=k;i++) cin>>zhi[i];
    for(int i=1;i<=n;i++) cin>>yuan[i];
    for(int i=1;i<=n;i++) zhui[i]=zhui[i-1]+yuan[i];
    ll ans=-1;
    for(int i=0;i<=(1<<k);i++){
        ll cnt=0;
        for(int j=1;j<=k;j++){
            ll now1=(1<<(j-1));
            if(now1&i) cnt+=zhi[j];
        }
        for(int j=1;j<=k;j++){
            ll now1=(1<<(j-1));
            if(i&now1) continue;
            int biao=upper_bound(zhui+dp[i],zhui+1+n,zhui[dp[i]]+zhi[j])-zhui-1;
            dp[i^now1]=max(dp[now1^i],biao);
            if(dp[i^now1]==n){
                ll now2=i^now1,now4=0;
                for(int p=1;p<=k;p++){
                    ll now3=(1<<(p-1));
                    if((now2&now3)==0){
                        now4+=zhi[p];
                    }
                }
                ans=max(ans,now4);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2021-05-20 10:45  14long  阅读(82)  评论(0)    收藏  举报