题意 : 有 k ≤ 16 k \leq16 k≤16枚硬币,每枚价值 a [ i ] ≤ 1 e 8 a[i] \leq 1e8 a[i]≤1e8,有 m ≤ 1 e 6 m\leq1e6 m≤1e6件物品, 每件物品 c o s t [ i ] ≤ 1 e 4 cost[i]\leq1e4 cost[i]≤1e4, 而且必须顺序买, 问在不找零的情况下自己最多能剩多少钱
>> face <<
Strategy:状压DP, i是一个表示二进制的十进制数,'1’是当前位置的硬币被选了
状态: dp[i]->状态为i所能顺序买最远物品的下标
目标: 所有dp[i] = m 的i里对应的0位(没有选的硬币),的价值的最大值
边界: dp[0] = 0;
合法判断: 无
转移方程:
d p [ i ∣ 1 < < j − 1 ] = m a x ( d p [ i ∣ 1 < < j − 1 ] , u p p e r b o u n d ( s u m , s u m + m , s u m [ d p [ i ] ] + a [ j ] ) − s u m ) dp[i | 1 << j - 1] = max(dp[i | 1 << j - 1], upperbound(sum, sum + m, sum[dp[i]] + a[j]) - sum) dp[i∣1<<j−1]=max(dp[i∣1<<j−1],upperbound(sum,sum+m,sum[dp[i]]+a[j])−sum)
attention: 转移方程一定要缜密
双倍经验: 注意转移方程
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define all(a) a.begin(), a.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cout << #x << " is " << x << endl
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define lowbit(x) x &(-x)
#define bin(x) cout << #x << " is " << bitset<sizeof(int) * 2>(x) << endl
#define pi acos(-1.0)
using namespace std;
using namespace __gnu_pbds;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
ll sum[maxn], a[17];
ll n, m, money[maxn];
int dp[1 << 16];
const db eps = 1e-8;
int main()
{
ios::sync_with_stdio(0);
cin >> n >> m;
_rep(i, 1, n){
cin >> a[i];
}
_rep(i, 1, m){
ll x;
cin >> x;
sum[i] = sum[i - 1] + x;
}
_rep(i, 0, (1 << n) - 1){
_rep(j, 1, n){
if(i >> j - 1 & 1)
continue;
dp[ i | 1 << j - 1] = max(dp[i | 1 << j - 1], (int)(upper_bound(sum + 1, sum + 1 + m, sum[dp[i]] + a[j]) - sum - 1));
}
}
ll ans = -1;
_rep(i, 0, (1 << n) - 1){
if(dp[i] == m){
ll left = 0;
_rep(j, 1, n){
if(!(i >> j - 1 & 1)){
left += a[j];
}
}
ans = max(ans, left);
}
}
cout << ans << endl;
}
第一次回顾, 重点:转移方程的转移
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
using namespace std;
const int maxn = 1e5 + 10;
const int mod = 9999973;
int dp[1 << 16], a[22], sum[maxn], n, m;
int main()
{
ios::sync_with_stdio(0);
cin >> n >> m;
_rep(i, 1, n)
{
cin >> a[i];
}
_rep(i, 1, m)
{
int xx;
cin >> xx;
sum[i] = sum[i - 1] + xx;
}
_rep(i, 0, (1<< n) - 1){
_rep(j,1, n){
if(!(i >> j - 1 & 1)){
dp[i | 1 << j - 1] = max(dp[i | 1 << j - 1], (int)(upper_bound(sum + 1, sum + 1 + m, sum[dp[i]] + a[j]) - sum - 1));
}
}
}
ll ans = -1;
_rep(i, 0, (1<< n)-1){
if(dp[i] == m){
ll tmp = 0;
_rep(j, 1, n){
if(!(i >> j - 1 & 1)){
tmp += a[j];
}
}
ans = max(ans , tmp);
}
}
cout << ans << endl;
}