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

(color{#0066ff}{题目描述})

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

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

(color{#0066ff}{输入格式})

第一行,两个正整数 N 和 M((1 leq N leq 40,1 leq M leq 10^{18})),表示比赛的个数和 Bobek 那家徒四壁的财产。

第二行,N 个以空格分隔的正整数,均不超过 (10^{16}) ,代表每场比赛门票的价格。

(color{#0066ff}{输出格式})

输出一行,表示方案的个数。由于 N 十分大,注意:(答案 le 2^{40})

(color{#0066ff}{输入样例})

5 1000
100 1500 500 500 1000

(color{#0066ff}{输出样例})

8

(color{#0066ff}{题解})

meet in the middle 对抗搜索

(O(2^{40} o 2^{20}+2^{20} o 2^{21}))

合并中间量用upperbound

注意,不能用lowerbound,因为可能有相同价钱的方案,都要算上

#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define _ 0
#define LL long long
#define Space putchar(' ')
#define Enter putchar('
')
#define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
#define fu(x,y,z)  for(int x=(y),x##end=z;x<x##end;x++)
#define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
#define fd(x,y,z)  for(int x=(y),x##end=z;x>x##end;x--)
#define mem(x,y)   memset(x,y,sizeof(x))
#ifndef olinr
inline char getc()
{
	static char buf[100001],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
template<typename T>inline void in(T &x)
{
	int f=1; char ch; x=0;
	while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
	while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
	x*=f;
}
LL n,m;
LL a[1<<21],b[1<<21],s[50];
int num1,num2,mid;
LL ans;
inline void dfs1(int dep,LL tot)
{
	if(tot>m) return;
	if(dep==mid+1)
	{
		a[++num1]=tot;
		return;
	}
	dfs1(dep+1,tot);
	dfs1(dep+1,tot+s[dep]);
}
inline void dfs2(int dep,LL tot)
{
	if(tot>m) return;
	if(dep==n+1)
	{
		b[++num2]=tot;
		return;
	}
	dfs2(dep+1,tot);
	dfs2(dep+1,tot+s[dep]);
}
int main()
{
	in(n),in(m);
	fuu(i,1,n) in(s[i]);
	mid=(1+n)>>1;
	dfs1(1,0LL);
	dfs2(mid+1,0LL);
	std::sort(a+1,a+num1+1);
	fuu(i,1,num2) ans+=std::upper_bound(a+1,a+num1+1,m-b[i])-a-1;
	printf("%lld",ans);
	return ~~(0^_^0);
}
原文地址:https://www.cnblogs.com/olinr/p/10060596.html