当前位置:首页 > 编程笔记 > 正文
已解决

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

来自网友在路上 146846提问 提问时间:2023-11-01 23:53:19阅读次数: 46

最佳答案 问答题库468位专家为你答疑解惑

Portal.

折半搜索(meet in the middle)。

首先考虑正常的搜索,时间复杂度 O ( 2 40 ) O(2^{40}) O(240)

所以考虑折半搜索,从两边对着搜,具体就是搜索 1 ∼ n 2 1\sim\dfrac{n}{2} 12n n 2 + 1 ∼ n \dfrac{n}{2}+1\sim n 2n+1n 两个区间内的最优解。这样优化之后,时间复杂度就变为 O ( 2 n 2 + 1 ) O(2^{\frac{n}{2}+1}) O(22n+1)

第一遍搜索前半部分时,我们的限制是不超过 M M M。可以记录此时对于一个合法方案,它的消耗钱数 sum 是多少。

到了第二遍搜索后半部分时,需要知道的是,我们可以统计的方案是前后加一起小于 M M M 的方案。于是乎我们先对第一次得到的方案进行 sort,枚举选后一半的所有情况,如果和前一半合并之后总钱数仍小于 M M M,可以把这些可能全部累计到 ans 中。由于前一半的方案已经被我们排成有序的了,所以我们可以用 upper_bound 函数快速查找出可以统计的情况。

具体代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long// 对于此题的两次 DFS 来说,要统计 1 个 sum(当前消耗钱数)和 pos(已经搜到哪里了)const int maxn=1<<25;//左移 25 位相当于 2 的 25 次方
int q1[maxn],q2[maxn],co[45],ans,N,M,cnt1,cnt2,mid;void dfs1(int sum,int pos)
{if(sum>M) return;if(pos>mid) {q1[++cnt1]=sum;return;}dfs1(sum+co[pos],pos+1);dfs1(sum,pos+1);//考虑不选当前位,继续向下搜
}void dfs2(int sum,int pos)
{if(sum>M) return;if(pos>N) {q2[++cnt2]=sum;return;}dfs2(sum+co[pos],pos+1);dfs2(sum,pos+1);
}signed main()
{cin>>N>>M;mid=(N+1)/2;for(int i=1;i<=N;i++) cin>>co[i];dfs1(0,1);sort(q1+1,q1+cnt1+1);dfs2(0,mid+1);for(int i=1;i<=cnt2;i++)ans+=upper_bound(q1+1,q1+cnt1+1,M-q2[i])-q1-1;// cout<<cnt<<endl;// cout<<N/2<<endl;cout<<ans;return 0;
}
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"P4799 [CEOI2015 Day2] 世界冰球锦标赛":http://eshow365.cn/6-29713-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!