看到这题,二分是很容易想到的,然后就是这么判断当前根数是不是可行
一开始我想的是贪心,我想过如下贪心,但都被自己造的数据叉了:
1.当前这跟根用比它稍长一点的木棍截取
数据:2
31 50
4
20 15 15 15 16
2.长的用长的截取,或短的用长的截取
数据:3
40 45 50
6
35 10 20 20 20 30
最后发现当前木棍不一定只用最长的或是稍长于它的截取,可能用长度中等的木棍截取
所以只能暴力
但是暴力是50^1000的,就算不跑满也很大了
所以我加了一个前缀和优化,如果剩下的所有木棍的总长小于一根木棍,直接返回可行
交了一发,发现T了
然后发现后续搜索的不可行方案实在太多了,所以我设了一个3e6的阈值
直接ac了
/**************************************************************
Problem: 1082
User: syh0313
Language: C++
Result: Accepted
Time:4824 ms
Memory:1572 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using
namespace
std;
const
int
maxn=1010;
int
n,m,l,r,ans,topt,a[maxn],len[maxn],sum[maxn];
bool
f;
struct
data {
int
c[51];};
void
dfs(
int
x,data now)
{
if
(f)
return
;
if
(x==0) {f=1;
return
;}
topt++;
if
(topt>3000000)
return
;
int
ma=0;
for
(
int
i=1;i<=n;i++)
{
if
(now.c[i]>=sum[x]) {f=1;
return
;}
ma=max(ma,now.c[i]);
}
if
(ma<len[x])
return
;
for
(
int
i=1;i<=n;i++)
if
(now.c[i]>=len[x])
{
data to=now; to.c[i]-=len[x];
if
(!f) dfs(x-1,to);
else
break
;
}
}
bool
ok(
int
k)
{
data x; f=0; topt=0;
for
(
int
i=1;i<=n;i++) x.c[i]=a[i];
dfs(k,x);
return
f;
}
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"
,&len[i]);
sort(len+1,len+m+1); l=0; r=m;
for
(
int
i=1;i<=m;i++) sum[i]=sum[i-1]+len[i];
while
(l<=r)
{
int
mid=(l+r)>>1;
if
(ok(mid)) {l=mid+1; ans=max(ans,mid);}
else
r=mid-1;
}
printf
(
"%d\n"
,ans);
return
0;
}