[总结]折半搜索

例2:P4799 [CEOI2015 Day2]世界冰球锦标赛

分析:
当我们使用搜索解决这道题时,我们会发现传统的搜索方式无法满足本题N<=40(即产生\(2^{40}\)个搜索结果)的数据范围。

因此,本题使用折半搜索算法,将这N个数分为1~n/2n/2+1~n两组,并分别进行搜索处理,得到每组内元素可以组合成的数字。随后,我们令任意一组结果有序(这里为第二组),依次扫描第一组元素并不断累计由该元素和第二组元素组成的不超过M的数的个数,最终累计后的结果就是本题的答案。

代码如下:

#include<bits/stdc++.h>
#define N 1100000
#define ll long long
using namespace std;
int n,cnt1,cnt2;
ll sum1[N],sum2[N];
ll w[N],ans=0,c;
void DFS_fir(int dep,ll sum){
	if(sum>c) return;
	if(dep>n/2){
		if(sum<=c) sum1[++cnt1]=sum;
		return;
	}
	DFS_fir(dep+1,sum+w[dep]);
	DFS_fir(dep+1,sum);
}
void DFS_sec(int dep,ll sum){
	if(sum>c) return;
	if(dep>n)
	{
		if(sum<=c) sum2[++cnt2]=sum;
		return;
	}
	DFS_sec(dep+1,sum+w[dep]);
	DFS_sec(dep+1,sum);
}
int main()
{
	scanf("%d%lld",&n,&c);
	for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
	DFS_fir(1,0);
	DFS_sec(n/2+1,0);
	sort(sum2+1,sum2+cnt2+1);
	for(int i=1;i<=cnt1;i++)
		ans+=upper_bound(sum2+1,sum2+cnt2+1,c-sum1[i])-sum2-1;
	printf("%lld",ans);
	return 0;
}
posted @ 2019-10-28 21:07  Wolfloral  阅读(420)  评论(0编辑  收藏  举报