[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. wireshark怎么抓包、wireshark抓包详细图文教程(转)

    wireshark怎么抓包.wireshark抓包详细图文教程 wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示网络封包的详细信息.使用wireshark的人必 ...

  2. 最长回文子串(Mirrored String II)

    Note: this is a harder version of Mirrored string I. The gorillas have recently discovered that the ...

  3. struts2结合axis开发webservice

    第一步:引入axis的依赖jar包  第二步:修改web.xml文件  <listener> <listener-class>org.apache.axis.transport ...

  4. js点击按钮获取验证码倒计时

    //发送验证码倒计时 var clock = ''; var nums = 60; var btn; $("#btnGetVerCode").click(function () { ...

  5. C#获取访问者ip和获取本机ip地址

    获取访问者ip: string userIP; // HttpRequest Request = HttpContext.Current.Request; HttpRequest Request = ...

  6. 配置SecureCRT连接VirtualBox虚拟机中的Linux环境

    在实际的运维中我们常常使用SecuriteCRT来远程控制Linux服务器.下面将详细介绍windows 7下通过VirtualBox搭建linux开发环境,并最终通过SecurityCRT来远程访问 ...

  7. Docker学习笔记_安装和使用Zookeeper

    一.准备 1.宿主机OS:Win10 64位 2.虚拟机OS:Ubuntu18.04 3.账号:docker 二.安装 1.搜索镜像                                  ...

  8. 面试题:Java必知必会:异常机制详解 背1

    一.Java异常概述 在Java中,所有的事件都能由类描述,Java中的异常就是由java.lang包下的异常类描述的. Trowable是所有异常的超类.  他的常用方法printStackTrec ...

  9. NUMA微架构

    NUMA微架构 written by qingran September 8th, 2011 no comment 现在开始补日志,逐步的扫清以前写了一半的和"欠账未还的".半年之 ...

  10. 使用EasyUI,关于日期格式的文本框按照正常方式获取不到值的问题

    这是个小菜在实际工作中遇到的问题,相信很多EasyUI新手很可能也遇到这样的问题,因此小菜觉得有必要拿出来分享一下. 这个问题要从EasyUI的datebox组件说起,小菜用这个组件的时候,发现用$( ...