[SCOI2005]栅栏

link

搜索题。

我真的不想写搜索啊,这玩意复杂度没法证,能拿多少分得看数据和评测机,而且没有固定思路,就像某些埋头堆硬件的厂家,写起来只有那么难受了。

关于这道题。有一个显而易见的贪心,最后锯出来的木条一定是最小的那些,因为长木条可以锯出来,短木条一定可以,转换方案之后肯定是不劣的。然后就考虑二分,用 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;
}
posted @ 2022-07-05 14:25  Feyn618  阅读(26)  评论(0编辑  收藏  举报