#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=100005;
int n,m,ans=-1,tot,maxn,bj;
int a[20],b[N],f[N],sum[N];
inline int calc(int x,int y){通过前缀和,二分答案,找到用这枚硬币能够买到的最多的物品
if(x==m)return m;
int l=x+1,r=m,pos=x;
while(l<=r){
int mid=(l+r)>>1;
if(sum[mid]-sum[x]<=y)pos=mid,l=mid+1;
else r=mid-1;
}
return pos;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)a[i]=read(),tot+=a[i],maxn=max(maxn,a[i]);
for(int i=1;i<=m;++i)b[i]=read(),sum[i]=sum[i-1]+b[i];
for(int i=1;i<=m;++i)if(maxn<b[i]){puts("-1");return 0;}
if(tot<sum[n]){puts("-1");return 0;}//两个特判.
for(int j=1;j<(1<<n);++j)
for(int i=1;i<=n;++i)
if(j&(1<<(i-1)))f[j]=max(f[j],calc(f[j^(1<<(i-1))],a[i]));//记得取max!
for(int j=1;j<(1<<n);++j){
if(f[j]==m){
int cnt=tot;
for(int i=1;i<=n;++i)if(j&(1<<(i-1)))cnt-=a[i];
ans=max(ans,cnt);
}
}
printf("%d\n",ans);
return 0;
}
原文:https://www.cnblogs.com/PPXppx/p/11726009.html