BZOJ_4800_[Ceoi2015]Ice Hockey World Championship_双指针

BZOJ_4800_[Ceoi2015]Ice Hockey World Championship_双指针

Description

有n个物品,m块钱,给定每个物品的价格,求买物品的方案数。

Input

第一行两个数n,m代表物品数量及钱数
第二行n个数,代表每个物品的价格
n<=40,m<=10^18

Output

一行一个数表示购买的方案数
(想怎么买就怎么买,当然不买也算一种)

Sample Input

5 1000
100 1500 500 500 1000

Sample Output

8

把序列分成两半,分别搜出所有状态。然后排个序双指针解决。
 
代码:
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
typedef unsigned long long ll;
int n,mid;
ll w[50],a[2000050],b[2000050],m;
int la,lb;
void dfs1(int dep,ll sum) {
	if(dep==mid) {
		a[++la]=sum; return ;
	}
	if(w[dep+1]+sum<=m) dfs1(dep+1,sum+w[dep+1]);
	dfs1(dep+1,sum);
}
void dfs2(int dep,ll sum) {
	if(dep==n) {
		b[++lb]=sum; return ;
	}
	if(w[dep+1]+sum<=m) dfs2(dep+1,sum+w[dep+1]);
	dfs2(dep+1,sum);
}
int main() {
	//freopen("shopping.in","r",stdin);
	//freopen("shopping.out","w",stdout);
	scanf("%d%llu",&n,&m);
	int i;
	for(i=1;i<=n;i++) {
		scanf("%llu",&w[i]);
	}
	if(n==1) {
		printf("%d\n",1+(w[1]<=m)); return 0;
	}
	mid=(n+1)>>1;
	dfs1(0,0);
	dfs2(mid,0);
	int j=lb;
	sort(a+1,a+la+1); sort(b+1,b+lb+1);
	ll ans=0;
	for(i=1;i<=la;i++) {
		while(j&&b[j]+a[i]>m) j--;
		if(j==0) break;
		ans+=j;
	}
	printf("%llu\n",ans);
}

 

posted @ 2018-05-26 13:52  fcwww  阅读(123)  评论(0编辑  收藏  举报