折半搜索【p4799】[CEOI2015 Day2]世界冰球锦标赛

Description

今年的世界冰球锦标赛在捷克举行。Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念。他只是单纯的想去看几场比赛。如果他有足够的钱,他会去看所有的比赛。不幸的是,他的财产十分有限,他决定把所有财产都用来买门票。

给出 Bobek 的预算和每场比赛的票价,试求:如果总票价不超过预算,他有多少种观赛方案。如果存在以其中一种方案观看某场比赛而另一种方案不观看,则认为这两种方案不同。

Input

第一行,两个正整数 NM(1N40,1M1018),表示比赛的个数和 Bobek 那家徒四壁的财产。

第二行,N 个以空格分隔的正整数,均不超过 1016,代表每场比赛门票的价格。

Output

输出一行,表示方案的个数。由于 N 十分大,注意:答案 240

显然这个题直接dfs是过不去的O(2n)

但是我们可以一半一半的搜,即折半搜索,复杂度可以降到O(2n2)

所以我们取一个mid,分别搜前半段和后半段。

然后合并答案的时候就需要令某一个数组变得有序,在其中找到最靠右的合法位置,直接累加即可。

这里用到了upper_bound

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register
#define lo long long

using namespace std;

const int gz=1e6+6e5;

inline void in(R lo &x)
{
	R int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}

lo a[gz],b[gz],mon[42],ans,m;

int sum,cnt,n,mid;

void dfs(R int dep,R lo now)
{
	if(now>m)return;
	if(dep>mid)
	{
		a[++cnt]=now;
		return;
	}
	dfs(dep+1,now+mon[dep]);
	dfs(dep+1,now);
}

void dfss(R int dep,R lo now)
{
	if(now>m)return;
	if(dep>n)
	{
		b[++sum]=now;
		return;
	}
	dfss(dep+1,now+mon[dep]);
	dfss(dep+1,now);
}

int main()
{
	scanf("%d%lld",&n,&m);
	for(R int i=1;i<=n;i++)in(mon[i]);
	mid=(n+1)/2;
	dfs(1,0);dfss(mid+1,0);
	sort(b+1,b+sum+1);
	for(R int i=1;i<=cnt;i++)
		ans+=upper_bound(b+1,b+sum+1,m-a[i])-b-1;
	printf("%lld",ans);
}
posted @   顾z  阅读(362)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示