您的位置:首页 > 其它

BZOJ 4800 [Ceoi2015]Ice Hockey World Championship ……

2017-08-24 18:33 387 查看

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

HINT

传送门
题意就是01背包然后问有几种方法。
然而n不大而且体积非常非常大。
如果n只有20,30这样就可以直接dfsAC了……然而n=40又不是纯正的暴力。

这时可以萌生出2^(n/2)的想法……
我们先求出前20个数01背包的2^20的情况;然后求出后20个的2^20.
对于前20个数的情况x,花费体积V[x],那么只要找到
在后20个数内,值<=m-V[x]的个数。

所以只要把后20个的所有情况求出来放入数组;
排个序然后二分统计答案即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll read(){
ll x=0LL,f=1LL;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=1050000;
int n,len[2];
ll V,a[45];
ll num[2]
;
void dfs(int now,int end,ll v,bool f){
if (now>end){
num[f][++len[f]]=v;
return;
}
if (v+a[now]<=V) dfs(now+1,end,v+a[now],f);
dfs(now+1,end,v,f);
}
int BS(ll x){
int L=1,R=len[1],mid;
while (L<R){
mid=(L+R+1)>>1;
if (num[1][mid]<=x) L=mid;
else R=mid-1;
}
return L;
}
int main(){
n=(int)read(),V=read();
for (int i=1;i<=n;i++) a[i]=read();
len[0]=len[1]=0;
dfs(1,(n>>1),(ll)0,0);
dfs((n>>1)+1,n,(ll)0,1);

sort(num[1]+1,num[1]+1+len[1]);

ll ans=(ll)0;
for (int i=1;i<=len[0];i++)
ans+=(ll)BS(V-num[0][i]);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: