[CEOI2015 Day2]世界冰球锦标赛

题目描述

译自 CEOI2015 Day2 T1「Ice Hockey World Championship」

今年的世界冰球锦标赛在捷克举行。\(Bobek\) 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念。他只是单纯的想去看几场比赛。如果他有足够的钱,他会去看所有的比赛。不幸的是,他的财产十分有限,他决定把所有财产都用来买门票。

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

输入输出格式

输入格式:

第一行,两个正整数 \(N\) 和 \(M(1 \leq N \leq 40,1 \leq M \leq 10^{18})\),表示比赛的个数和 \(Bobek\) 那家徒四壁的财产。

第二行,\(N\) 个以空格分隔的正整数,均不超过 \(10^{16}\),代表每场比赛门票的价格。

输出格式:

输出一行,表示方案的个数。由于 \(N\) 十分大,注意:答案 \(\le 2^{40}\)。

输入输出样例

输入样例#1:

5 1000
100 1500 500 500 1000

输出样例#1:

8

说明

样例解释

八种方案分别是:

  • 一场都不看,溜了溜了
  • 价格 \(100\) 的比赛
  • 第一场价格 \(500\) 的比赛
  • 第二场价格 \(500\) 的比赛
  • 价格 \(100\) 的比赛和第一场价格 \(500\) 的比赛
  • 价格 \(100\) 的比赛和第二场价格 \(500\) 的比赛
  • 两场价格 \(500\) 的比赛
  • 价格 \(1000\) 的比赛

有十组数据,每通过一组数据你可以获得 \(10\) 分。各组数据的数据范围如下表所示:

数据组号 1-2 3-4 5-7 8-10
$N \leq $ \(10\) \(20\) \(40\) \(40\)
\(M \leq\) \(10^6\) \(10^{18}\) \(10^6\) \(10^{18}\)

题解

首先看数据范围

  1. 1-4组数据\(N\leq20\),爆搜就可以解决。

    inline void dfs(R ll dep,R ll sum){
    if(sum>m)return;
    if(dep==n+1){
    ans++;
    return;
    }
    dfs(dep+1,sum+a[dep]);
    dfs(dep+1,sum);
    }
    int main(){
    read(n);read(m);
    for(R int i=1;i<=n;i++)read(a[i]);
    if(n<=20){
    dfs(1,0);
    printf("%lld\n",ans);
    }
    return 0;
    }
  2. 5-7组数据\(M\leq10^6\),裸的背包啊。

    int main(){
    read(n);read(m);
    for(R int i=1;i<=n;i++)read(a[i]);
    if(m<=1e6){
    f[0]=1;
    for(R int i=1;i<=n;i++)
    for(R int j=m;j>=a[i];j--)
    f[j]+=f[j-a[i]];
    for(R int i=0;i<=m;i++)ans+=f[i];
    printf("%lld\n",ans);
    }
    return 0;
    }
  3. 现在你已经能拿到70分了(但在洛谷上是47分)

下面引出主角——折半搜索(meet in the middle思想)

因为\(N\leq40\) \(O(2^{40})\)的爆搜一定会\(TLE\),所以我们将\(N\)分成两份

搜索\(1\)到\(n/2\)和\(n/2+1\)到\(n\),让复杂度降到\(O(2^{n/2+1})\)。

画一个图(网上找的不错的图)理解一下为什么能降低复杂度

inline void dfs(R int l,R int r,R ll sum,R ll a[],R ll &cnt){
if(sum>m)return;
if(l>r){
a[++cnt]=sum;
return;
}
dfs(l+1,r,sum+w[l],a,cnt);//选
dfs(l+1,r,sum,a,cnt);//不选
}

将前一半的搜索状态存入a数组,后一半存入b数组。

mid=n/2;
dfs(1,mid,0,suma,cnta);
dfs(mid+1,n,0,sumb,cntb);

一般\(meet\) \(in\) \(the\) \(middle\)的难点主要在于最后答案的组合统计。

我们可以现将a或b数组sort,让其有序。

然后通过枚举另一个数组中的状态,来实现统计答案。

上述找\(pos\)的过程可以通过upper_bound()完成。

sort(suma+1,suma+1+cnta);//使一个数组有序
for(R int i=1;i<=cntb;i++)
ans+=upper_bound(suma+1,suma+1+cnta,m-sumb[i])-suma-1;//统计ans

下面是高清完整code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#define ll long long
#define R register
#define N 55
using namespace std;
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
a=f*x;
}
ll n,m,w[N],mid,suma[1<<21],sumb[1<<21],cnta,cntb,ans;
inline void dfs(R int l,R int r,R ll sum,R ll a[],R ll &cnt){
if(sum>m)return;
if(l>r){
a[++cnt]=sum;
return;
}
dfs(l+1,r,sum+w[l],a,cnt);
dfs(l+1,r,sum,a,cnt);
}
int main(){
read(n);read(m);
for(R int i=1;i<=n;i++)read(w[i]);
mid=n>>1;
dfs(1,mid,0,suma,cnta);
dfs(mid+1,n,0,sumb,cntb);
sort(suma+1,suma+1+cnta);
for(R int i=1;i<=cntb;i++)
ans+=upper_bound(suma+1,suma+1+cnta,m-sumb[i])-suma-1;
printf("%lld\n",ans);
return 0;
}

这里还有一道折半搜索的好题,难度升级——luogu,还有 my blog.

【BZOJ4800】[CEOI2015 Day2]世界冰球锦标赛 (折半搜索)的更多相关文章

  1. [luogu4799 CEOI2015 Day2] 世界冰球锦标赛(折半搜索)

    传送门 Solution 折半搜索裸题,注意\(long long\) Code #include <cmath> #include <cstdio> #include < ...

  2. 【题解】P4799[CEOI2015 Day2]世界冰球锦标赛

    [题解][P4799 CEOI2015 Day2]世界冰球锦标赛 发现买票顺序和答案无关,又发现\(n\le40\),又发现从后面往前面买可以通过\(M\)来和从前面往后面买的方案进行联系.可以知道是 ...

  3. [CEOI2015 Day2]世界冰球锦标赛 (双向搜索)

    题目描述 [CEOI2015 Day2]世界冰球锦标赛译自 CEOI2015 Day2 T1「Ice Hockey World Championship」 今年的世界冰球锦标赛在捷克举行.Bobek ...

  4. 题解 P4799 【[CEOI2015 Day2]世界冰球锦标赛】

    题解 P4799 [[CEOI2015 Day2]世界冰球锦标赛] 双向搜索好题 传送门 实际上,双向搜索就是把\(a^n\)的复杂度转变成了大多为\(O(nlogna^{\frac{n}{2}})\ ...

  5. 折半搜索【p4799】[CEOI2015 Day2]世界冰球锦标赛

    Description 今年的世界冰球锦标赛在捷克举行.Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念.他只是单纯的想去看几场比赛.如果他有足够的钱,他会去看所有的比赛.不幸的是,他 ...

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

    \(\color{#0066ff}{题目描述}\) 今年的世界冰球锦标赛在捷克举行.Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念.他只是单纯的想去看几场比赛.如果他有足够的钱,他会 ...

  7. P4799 [CEOI2015 Day2]世界冰球锦标赛(折半暴搜)

    题目很明确,不超过预算的方案数.两个直觉:1.暴搜2.dp 每个点两种状态,选或不选.... 1.可过20% 2.可过70% 正解:折半搜索(meet in the middle) 有点像以前的双向广 ...

  8. 洛谷P4799 世界冰球锦标赛 CEOI2015 Day2 meet-in-the-middle

    正解:折半搜索 解题报告: 先放个传送门QAQ 想先说下部分分?因为包含了搜索背包两个方面就觉得顺便复习下?QwQ 第一档部分分 爆搜 就最最普通的爆搜鸭,dfs(第几场,钱),然后每次可以看可以不看 ...

  9. [题解](折半搜索)luogu_P4799_BZOJ_4800世界冰球锦标赛

    抄的题解 以及参考:https://www.cnblogs.com/ZAGER/p/9827160.html 2^40爆搜过不了,考虑折半搜索,难点在于合并左右的答案,因为有可能答案同时载左右两边,我 ...

随机推荐

  1. Java微信公众平台开发(十五)--微信JSSDK的使用

    转自:http://www.cuiyongzhi.com/post/63.html 在前面的文章中有介绍到我们在微信web开发过程中常常用到的 [微信JSSDK中Config配置] ,但是我们在真正的 ...

  2. 玩转angularJs——通过自定义ng-model,不仅仅只是input可以实现双向数据绑定

    体验更优排版请移步原文:http://blog.kwin.wang/programming/angularJs-user-defined-ngmodel.html angularJs双向绑定特性在开发 ...

  3. Oracle11g-BBED安装

    oracle 11g中缺bbed包 下载地址: https://pan.baidu.com/s/19DVvIajarDjnynILNwQDWQ 密码:tmqt 1.BBED的安装 1.上传(sbbdp ...

  4. Tornado 高并发源码分析之三--- Application 对象

    Application 对象主要工作: 服务器启动时: 1.在新建一个app的时候,根据设置好的 URL 和回调函数 Handler 封装成URLSpec 对象   服务器运行时: 2.在请求到来,将 ...

  5. PyInstaller打包成exe可执行文件

    PyInstaller 安装pyinstaller 对于那些网络比较稳定,能够流畅使用pip源地址的用户,直接下面的命令就可以搞定: pip install pyinstaller 通常我们会下载源码 ...

  6. linux中ftp配置文件详解

    vsftpd配置文件采用"#"作为注释符,以"#"开头的行和空白行在解析时将被忽略,其余的行被视为配置命令行,每个配置命令的"="两边不要留 ...

  7. 使用ssh-agent管理密钥

    ssh-agent是ssh代理程序,使用ssh-agent可以方面管理私钥. ssh-agent主要使用在如下两个场景: 1.使用不同的密钥连接不同主机,每次连接都要指定私钥; 2.当私钥设置了密码, ...

  8. 老外畅想C# 5.0这个可以有

    C# 5.0 - not quite there yet! 老外大胆的YY了一下,感觉挺有意思转发过来. 回顾C#发展的历史,C#1.0模仿了Java,并保留了C/C++的一些特性如struct,新学 ...

  9. 关于mysql自增字段问题

    最近遇到mysql字段的自增问题,需要临时处理一下,然后就顺便补补课,这样就有了这样一篇文章. 1.自增值是什么 他是一个字段属性,是用来创建唯一标识的列的 The AUTO_INCREMENT at ...

  10. Apache rotatelogs命令

    一.简介 rotatelogs 是 Apache 自带的管道日志程序,可以完美的实现日志的轮转功能. 二.语法 Usage: rotatelogs [-v] [-l] [-L linkname] [- ...