传送门
二分答案。
显然切最小的几块最优。
暴力枚举当前是从什么地方切出来的。
但是显然要TLE
于是乎我们可以召唤王**了。
王**の剪枝:
1.当前剩余木材大小小于最小需要木材就丢弃。
2.当前丢弃木材+所有需要木材>所有的木材就返回。
然后就水过了。
#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
int a[55],b[1005],sb[1005],bl[1005];
int n,m,tot,l,r,mi,fl,sa;
void dfs(int ak,int bk,int s){
if (bk==0) fl=1;
if (fl) return;
while (a[ak]<b[1]&&ak<=n){
s+=a[ak];
ak++;
}
if (ak>n||sb[bk]+s>sa) return;
int t=ak;
if (b[bk]==b[bk+1]&&bk!=mi) t=bl[bk+1];
for (;t<=n;t++)
if (a[t]>=b[bk]){
a[t]-=b[bk];
bl[bk]=t;
dfs(ak,bk-1,s);
a[t]+=b[bk];
}
}
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--;
tot=0;
for (int i=1;i<=n;i++)
if (a[i]>b[1]){
tot++;
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];
n=tot;
l=0;
r=m;
while (l<r){
mi=(l+r+1)/2;
fl=0;
dfs(1,mi,0);
if (fl) l=mi; else r=mi-1;
}
printf("%d",l);
return 0;
}