【BZOJ4800】 [Ceoi2015]Ice Hockey World Championship

4800: [Ceoi2015]Ice Hockey World Championship

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 68  Solved: 30
[Submit][Status][Discuss]

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

Source

sol:

meet in the middle

太感人了 我刚打完板子今天就看见一道题

具体来说 我们分开 对前20个和后20个做背包 将答案放到数组a和b中 给b排序。

当然 现在答案肯定不对 我们枚举a中每一个元素 在b中二分 看看贡献是多少

贡献就是b的下标。然后ans+=其即可。

复杂度$O(2^{20}log2^{20}+2^{20}*2+2^{20}log2^{20})$

//Meet In The Middle
/*In Search Of Life*/
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iomanip>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#define debug(x) cerr<<#x<<"="<<x<<endl
#define INF 0x7f7f7f7f
#define llINF 0x7fffffffffffll
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
inline int init()
{
    int now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c==‘-‘)ju=-1;
        else if(c>=‘0‘&&c<=‘9‘)
        {
            now=now*10+c-‘0‘;
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
inline long long llinit()
{
    long long now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c==‘-‘)ju=-1;
        else if(c>=‘0‘&&c<=‘9‘)
        {
            now=now*10+c-‘0‘;
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
ll a[1005];
ll res[3000005];
int n;ll m;
#ifdef unix
    #define LLD "%lld"
#else
    #define LLD "%I64d"
#endif
ll nex[3000005];
int pren=n/2;
ll pans=0;
ll ans=0;
int pcnt=0,ncnt=0;
int bSearch(int l,int r,ll x)
{
    int pos=-1;
    int mid=((l+r)>>1);
    while(l<=r)
    {
        mid=((l+r)>>1);
        if(res[mid]>x)
        {
            r=mid-1;
        }
        else
        {
            l=mid+1;
            pos=mid;
        }
    }
    return pos;
}
void predfs(int now,ll V)
{
    if(V>m)return;
    if(now==pren+1)
    {
        res[++pcnt]=V;
        return;
    }
    predfs(now+1,V+a[now]);
    predfs(now+1,V);
    return;
}
void nextdfs(int now,ll V)
{
    if(V>m)return;
    if(now==n+1)
    {
        nex[++ncnt]=V;
        return;
    }
    nextdfs(now+1,V+a[now]);
    nextdfs(now+1,V);
    return;
}
void MeetInTheMiddle()
{
    for(int i=1;i<=ncnt;i++)
    {
        ans+=bSearch(1,pcnt,m-nex[i]);
    }
    return;
}
int main()
{
    n=init();m=llinit();
    for(int i=1;i<=n;i++)
    {
        a[i]=llinit();
    }
    pren=n/2;
    predfs(1,0);
    nextdfs((n/2)+1,0);
    sort(res+1,res+pcnt+1);
    MeetInTheMiddle();
    printf(LLD,ans);
    return 0;
}

时间: 2024-11-08 04:18:22

【BZOJ4800】 [Ceoi2015]Ice Hockey World Championship的相关文章

【bzoj4800】: [Ceoi2015]Ice Hockey World Championship dfs

[bzoj4800]: [Ceoi2015]Ice Hockey World Championship N<=40所以如果直接dfs背包会TLE 考虑Meet-in-the-middle 如果把N个物品分成前后A B两段分别背包 分别在A B中可行的方案的花费记录在a b中 答案就是a[i]+b[j]<=M的个数 把a b排序 然后序列就是单调的了 两个指针扫一遍就好了 1 #include <cstdlib> 2 #include <cstring> 3 #inclu

【bzoj4800】[Ceoi2015]Ice Hockey World Championship 折半搜索

题目描述 有n个物品,m块钱,给定每个物品的价格,求买物品的方案数. 输入 第一行两个数n,m代表物品数量及钱数 第二行n个数,代表每个物品的价格 n<=40,m<=10^18 输出 一行一个数表示购买的方案数 (想怎么买就怎么买,当然不买也算一种) 样例输入 5 1000 100 1500 500 500 1000 样例输出 8 题解 裸的折半搜索meet-in-the-middle 由于直接爆搜肯定会TLE,考虑把整个序列分成左右两部分,对于每部分求出它所有可以消耗钱数的方案.然后考虑左右

[bzoj4800][Ceoi2015]Ice Hockey World Championship

来自FallDream的博客,未经允许,请勿转载,谢谢. 有n个物品,m块钱,给定每个物品的价格,求买物品的方案数 n<=40 m<=10^18 考虑双向宽搜,然后得到两个大小为2^20的数组,排序之后两个指针推一推计算答案即可. 排序最好用基数排序 #include<iostream> #include<cstdio> #include<cstring> #define MN 40 #define MM 1050000 #define N 32767 #d

[Ceoi2015]Ice Hockey World Championship

有n个物品,m块钱,给定每个物品的价格,求买物品的方案数. n<=40,m<=10^18 水题,meet in the middle裸题,随便搞搞,统计答案二分一下就没了 #include<cstdio> #include<algorithm> int n,sum;long long m,f[1500001],a[41],ans; void dfs(int x,long long now){ if(x>n/2){f[++sum]=now;return ;} dfs

【Codeforces】C. Ice Cave(bfs)

我了个草,这个题明明bfs不知道谁挂了个dfs+剪枝的标签... 从起点bfs一步一步搜,碰到X判断是不是终点,如果是终点就结束,如果为'.',那么把该位置改成X,坐标入队. #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<iostream> using namespace std; const int maxn = 505; cons

【HackerRank】Ice Cream Parlor

Sunny and Johnny together have M dollars which they intend to use at the ice cream parlour. Among N flavors available, they have to choose two distinct flavors whose cost equals M. Given a list of cost of N flavors, output the indices of two items wh

【POJ】3009 Curling 2.0 ——DFS

Curling 2.0 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11432   Accepted: 4831 Description On Planet MM-21, after their Olympic games this year, curling is getting popular. But the rules are somewhat different from ours. The game is

【转】对于杭电OJ题目的分类

[好像博客园不能直接转载,所以我复制过来了..] 1001 整数求和 水题1002 C语言实验题——两个数比较 水题1003 1.2.3.4.5... 简单题1004 渊子赛马 排序+贪心的方法归并1005 Hero In Maze 广度搜索1006 Redraiment猜想 数论:容斥定理1007 童年生活二三事 递推题1008 University 简单hash1009 目标柏林 简单模拟题1010 Rails 模拟题(堆栈)1011 Box of Bricks 简单题1012 IMMEDI

【转载】cmake编写

Cmake的输入是在源码目录下的CMakeLists.txt文件.这个文件可以用include或者 add_subdirectory 命令增加入其它的输入文件. 语法 CMakeList.txt文件是由注释.命令和空白字符组成. 注释是由 # 开始,到行结尾. 命令是由:命令名.(.空格分隔的参数.)组成. 例如:command (args….) 上面的command可以是一个命令名:或者是一个宏:也可以是一个函数名. args是以空格分隔的参数例表(如果参数中包含空格,则要加双引号) 除了用于