[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. Mybatis系列(四)映射文件

    转自:https://blog.csdn.net/chris_mao/article/details/48811507 Mybatis的真正强大,在于她对SQL的映射,这也是她吸引人的地方.实现相同的 ...

  2. oracle语言基础

    一.语言分类 1.DML(Data Manipulation Language,数据操作语言):用于对数据的操作. DML包括:(1)SELECT:查询数据 select * from temp;   ...

  3. Djano + Nginx + docker配置与管理

    在配置这个服务之前,应该对docker的基本安装与使用应该很熟悉了.下面开始直接不如正题 1.让我们创建一个名为myproject的空目录,并在src名称内添加另一个文件夹.src应该包含django ...

  4. Leetcode:Regular Expression Matching分析和实现

    题目大意是要求我们实现一个简单的正则表达式全匹配判断.其中正则表达式中只包含一般字符,以及全匹配字符.和变长字符*.其中.可以匹配一个字符,而*与前一个字符相关联,x*可以被看作任意多个x(0到正无穷 ...

  5. tomcat的配置文件有那些

    配置文件一般都在conf文件夹里,主要有server.xml,context.xml,tomcat_user.xml,web.xml四个常用配置文件,server主要是服务器设置的,例如端口设置,路径 ...

  6. Python04 range()方法的使用、turtle.textinput()方法和write()的使用、turtle.numinput()的使用

    1 range() 方法的使用 1.1 range方法介绍 range方法会返回一个range类型的对象,该对象会根据range方法的参数产生一些列整型数据 技巧01:range方法有三个参数,第一个 ...

  7. 496. Next Greater Element I 另一个数组中对应的更大元素

    [抄题]: You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subse ...

  8. 566. Reshape the Matrix矩阵重排

    [抄题]: In MATLAB, there is a very useful function called 'reshape', which can reshape a matrix into a ...

  9. Linux tmux

    一.简介 Tmux是一个用于终端复用的软件,它允许一个用户在一个终端窗口或远程终端会话中使用多个不同的终端会话.在同一个命令行接口处理多个程序,以及将程序从已经开始运行另外的程序的Unix shell ...

  10. Cookie存中文乱码的问题

    有个奇怪的问题:登录页面中使用Cookie存值,Cookie中要存中文汉字.代码在本地调试,一切OK,汉字也能顺利存到Cookie和从Cookie中读出,但是放到服务器上不管用了,好好的汉字成了乱码, ...