P4799 [CEOI 2015] 世界冰球锦标赛 (Day2)

P4799 [CEOI 2015] 世界冰球锦标赛 (Day2)

大意

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

思路

这个题目首先,我们发现对于每场的比赛,我们都可以选择看或者不看,那么我们就有 \(2^n\) 的暴力选或不选,但是既然如此,我们便可以考虑双向搜索,折半搜索,这样是 \(2 \times 2^{n/2}\) 的复杂度,显然能过,但是我们去考虑如何在中间拼接状态,然后这道题的状态比较简单,就是我们判断前后你选择的那一部分的价值加起来的和是否大于 \(m\),因此我们把搜索出来的状态放到两个数组里面,\(a,b\) 然后我们对于每一个 \(a_i\),显然能对其做出贡献的是 \(b_j \le m - a_i,j \in [1, size(b)]\) ,那么直接二分查找位置,第一个大于的,这个位置之前的显然能做出贡献。

代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long
const int MAXN = 45;
const int MAXT = (1 << 20) + 5;
int n, m;
int a[MAXN];
vector<int> x, y;
int tot1 = 0, tot2 = 0;

void dfs1(int now, int sp, int res){
	if(now > sp){
		if(res <= m) x.push_back(res);
		return;
	}
	dfs1(now + 1, sp, res);
	dfs1(now + 1, sp, res + a[now]);
}

void dfs2(int now, int sp, int res){
	if(now > sp){
		if(res <= m) y.push_back(res);
		return;
	}
	dfs2(now + 1, sp, res);
	dfs2(now + 1, sp, res + a[now]);
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for(int i = 1;i <= n;i ++){
		cin >> a[i];
	}
	int mid = n / 2;
	dfs1(1, mid, 0);
	dfs2(mid + 1, n, 0);
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
//	for(int now : x){
//		cout << now << ' ';
//	}
//	cout << '\n';
//	for(int now : y){
//		cout << now << ' ';
//	}
//	cout << '\n';
	int ans = 0;
	for(int now : y){
		int val = m - now;
		int pos = upper_bound(x.begin(), x.end(), val) - x.begin();
//		cout << val << ' ' << pos << '\n';
		ans += pos;
	}
	cout << ans << '\n';
	return 0;
}
posted @ 2025-12-17 13:46  To_Carpe_Diem  阅读(4)  评论(0)    收藏  举报