已解决
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} 1∼2n、 n 2 + 1 ∼ n \dfrac{n}{2}+1\sim n 2n+1∼n 两个区间内的最优解。这样优化之后,时间复杂度就变为 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 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: GWAS软件:GEMMA的安装和使用教程
- 下一篇: Fedora 32安装Kaldi