【BZOJ4800】[Ceoi2015]Ice Hockey World Championship Meet in the Middle
【BZOJ4800】[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
100 1500 500 500 1000
Sample Output
8
题解:一开始以为是某种搜索+剪枝,后来发现死活剪不掉啊。
正解是Meet in the Middle,什么是Meet in the Middle呢?先DFS出前20个物品的2^20种情况,再DFS出后20个物品的所有情况,然后将这些情况分别按总价钱排序,拿双指针扫一下就行了。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; int n,dep,n1,n2; ll ans; ll m,sum; ll v[50],s1[(1<<20)+10],s2[(1<<20)+10]; void dfs(int x) { if(x>dep) { if(dep==n/2) s1[++n1]=sum; else s2[++n2]=sum; return ; } if(sum+v[x]<=m) sum+=v[x],dfs(x+1),sum-=v[x]; dfs(x+1); } bool cmp(ll a,ll b) { return a>b; } int main() { scanf("%d%lld",&n,&m); int i,j; for(i=1;i<=n;i++) scanf("%lld",&v[i]); dep=n/2,dfs(1),dep=n,dfs(n/2+1); sort(s1+1,s1+n1+1),sort(s2+1,s2+n2+1); for(i=1,j=n2;i<=n1;i++) { while(s1[i]+s2[j]>m) j--; ans+=j; } printf("%lld",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<