考虑状态压缩优化. 用一个数组 f[1 << 16]
记录下某一个状态时浪费价值的最小值.
因为对于给定的状态, 金币的总价值确定, 可以很容易的结合记录下来的值推出当前买到哪一个商品, 再用前文所提到的二分更新状态.
理论复杂度(O(2^N logN))
#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x7f7f7f7f;
const int MAXN = 1e5 + 10;
inline int read()
{
int x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int N, K;
ll tot[1 << 16];
int c[MAXN], a[MAXN]; ll sum[MAXN];
int f[1 << 16];
int main()
{
cin>>K>>N;
for(int i = 0; i < K; i++) c[i] = read();
for(int i = 1; i <= N; i++) a[i] = read();
for(int i = 1; i <= N; i++) sum[i] = sum[i - 1] + a[i];
sum[N + 1] = (1LL << 60);
for(int i = 1; i < (1 << K); i++)
for(int j = 0; j < K; j++) if(i & (1 << j)) tot[i] += c[j];
memset(f, 0x7f, sizeof(f)); f[0] = 0;
ll ans = -(1LL << 60);
for(int state = 0; state < (1 << K); state++) if(f[state] != INF){
int cur = lower_bound(sum, sum + N + 2, tot[state] - f[state]) - sum;
for(int i = 0; i < K; i++) if(!(state & (1 << i))){
int tmp = (state | (1 << i));
int nxt = upper_bound(sum, sum + N + 2, sum[cur] + c[i]) - sum;
--nxt;
f[tmp] = min(1LL * f[tmp], f[state] + c[i] - (sum[nxt] - sum[cur]));
if(nxt == N) ans = max(ans, tot[((1 << K) - 1) ^ tmp]);
}
}
if(ans == -(1LL << 60)) puts("-1");
else cout<<ans<<endl;
return 0;
}