[SCOI2005]栅栏
搜索题。
我真的不想写搜索啊,这玩意复杂度没法证,能拿多少分得看数据和评测机,而且没有固定思路,就像某些埋头堆硬件的厂家,写起来只有那么难受了。
关于这道题。有一个显而易见的贪心,最后锯出来的木条一定是最小的那些,因为长木条可以锯出来,短木条一定可以,转换方案之后肯定是不劣的。然后就考虑二分,用 f(wh) 来代表 wh 到 mid 的木条选完之后的状态,之前的影响则直接强加在木材数组里(感觉还是很巧妙的)。有两个剪枝,一个是假如两个木条长度一样,那么第二个木条的选择位置不会比第一个更靠前。第二个是假如当前木材已经比最短的木条短,那么它就是被浪费的。浪费的长度累加到一定程度就可以直接返回。
这玩意得多练。
#include<bits/stdc++.h>
//#define feyn
const int N=1010;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
int m,n,all,now,a[N],b[N],sum[N];
bool dfs(int wh,int last,int waste){
if(wh==0)return true;
if(waste+now>all)return false;
for(int i=last;i<=n;i++){
if(a[i]>=b[wh]){
a[i]-=b[wh];
if(a[i]<b[1])waste+=a[i];
bool an=b[wh]==b[wh-1]?dfs(wh-1,i,waste):dfs(wh-1,1,waste);
if(a[i]<b[1])waste-=a[i];
a[i]+=b[wh];
if(an)return true;
}
}
return false;
}
signed main(){
#ifdef feyn
freopen("in.txt","r",stdin);
#endif
read(m);
for(int i=1;i<=m;i++){
read(a[i]);all+=a[i];
}
read(n);
for(int i=1;i<=n;i++)read(b[i]);
sort(b+1,b+n+1);
int l=0,r=0,mid;
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+b[i];
if(sum[i]<=all)r=i;
else break;
}
while(l<r){
mid=l+r+1>>1;now=sum[mid];
if(dfs(mid,1,0))l=mid;
else r=mid-1;
}
printf("%d",l);
return 0;
}
一如既往,万事胜意