卧薪尝胆,厚积薄发。
USACO2013NOV GOLD No Change
Date: Fri Sep 21 17:29:59 CST 2018 In Category: NoCategory

Description:

按顺序买 $n$ 个物品,有 $k$ 个硬币,不找零,最大化最后剩下的钱。
$1\le n \le 10000,1\le k \le 16$

Solution:

状压硬币,每次在前缀和数组中二分即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 100010
#define MAXM 17
int val[MAXM],p[MAXN],s[MAXN];
int f[1 << MAXM];
int main()
{
scanf("%d%d",&m,&n);
for(int i = 1;i <= m;++i)scanf("%d",&val[i]);
for(int i = 1;i <= n;++i)scanf("%d",&p[i]);
for(int i = 1;i <= n;++i)s[i] = s[i - 1] + p[i];
s[++n] = 0x3f3f3f3f;
int tot = (1 << m) - 1;
memset(f,0,sizeof(f));
int ans = -1;
for(int b = tot;b >= 0;--b)
{
int res = 0;
for(int i = 1;i <= m;++i)
{
if(b & (1 << (i - 1)))
{
int p = upper_bound(s,s + 1 + n,s[f[b]] + val[i]) - s - 1;
f[b ^ (1 << (i - 1))] = max(f[b ^ (1 << (i - 1))],p);
res += val[i];
}
}
if(f[b] == n - 1)ans = max(ans,res);;
}
cout << ans << endl;
return 0;
}
In tag: DP-状压DP
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡