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;
}

浙公网安备 33010602011771号