传送门biu~
先排序,二分最多能得到多少木板,显然要尽量选小的木板,当木材大小小于最小的木块时丢弃。记录当前丢弃的木材量,若加上mid块木板 > 所有的木材 则不合法。
#include<bits/stdc++.h>
using namespace std;
int m,n,mid;
bool flag;
int a[55],sa,b[1005],ch[1005],sb[1005];
void dfs(int now,int sum,int Left){
if(sum==0) flag=1;
while(now<=n && a[now]<b[1]){Left+=a[now];++now;}
if(flag || now>n) return;
if(Left+sb[mid]>sa) return;
int tmp=now,tmpnow=now,tmpsum=sum,tmpLeft=Left;
if(b[sum]==b[sum+1] && sum!=mid) tmp=ch[sum+1];
for(int i=tmp;i<=n;++i){
if(a[i]>=b[sum]){
ch[sum]=i;a[i]-=b[sum];
--sum;
dfs(now,sum,Left);
now=tmpnow;sum=tmpsum;Left=tmpLeft;a[i]+=b[sum];
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
while(b[m]>a[n]) --m;
int tot=0;
for(int i=1;i<=n;++i) if(a[i]>b[1]) a[++tot]=a[i];
n=tot;
for(int i=1;i<=n;++i) sa+=a[i];
for(int i=1;i<=m;++i) sb[i]=sb[i-1]+b[i];
int L=1,R=m,ans=0;
while(L<=R){
mid=L+R>>1;
flag=0;
dfs(1,mid,0);
if(flag) ans=mid,L=mid+1;
else R=mid-1;
}
printf("%d",ans);
return 0;
}