ACDREAM 1726 A Math game(折半枚举+hash)

题目链接:

http://acdream.info/problem?pid=1726

题意:

给定n 个数,和一个数看,判断k能否由其中的任意个数的和组成。

分析:

因为n最大为40,暴力枚举所有的情况 复杂度为 2^40 肯定TLE ,然后就想到了折半枚举

分成两半,先处理前n/2个数的组合的情况 ,把所得结果哈希一下,然后再枚举后一半

的所有情况,然后在哈希表里查找。时间复杂度为 O(2^(N/2));

代码如下:

#include <stdio.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define PB push_back
#define MP make_pair
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,l,h) for(int i=(l);i<=(h);++i)
#define DWN(i,h,l) for(int i=(h);i>=(l);--i)
#define CLR(vis) memset(vis,0,sizeof(vis))
#define MST(vis,pos) memset(vis,pos,sizeof(vis))
#define MAX3(a,b,c) max(a,max(b,c))
#define MAX4(a,b,c,d) max(max(a,b),max(c,d))
#define MIN3(a,b,c) min(a,min(b,c))
#define MIN4(a,b,c,d) min(min(a,b),min(c,d))
#define PI acos(-1.0)
#define INF 1000000000
#define LINF 1000000000000000000LL
#define eps 1e-8
#define LL long long
using namespace std;

const int MAXN=1<<20;
const int HASH = 1000007;

struct hashmap//建立哈希表
{
    LL a[MAXN];
    int head[HASH],next[MAXN],size;
    void init(){//初始化
        MST(head,-1);
        size=0;
    }
    bool find(LL val){//查找一个元素是否在哈希表内
        int tmp = (val%HASH + HASH)%HASH;
        for(int i = head[tmp];i!=-1;i=next[i])
            if(val==a[i]) return true;
        return false;
    }
    void add(LL val){//添加元素到哈希表中
        int tmp =(val%HASH+HASH)%HASH;
        if(find(val)) return;
        a[size]=val;
        next[size]=head[tmp];
        head[tmp]=size++;
    }
}h1;
int n,m,num[55];
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        h1.init();
        REP(i,n) scanf("%d",num+i);
        int t=n/2;
        REP(i,1<<t){
            LL sum=0;
            REP(j,t){
                if(i&(1<<j))
                    sum+=num[j];
            }
            if(sum>m) continue;
            h1.add(sum);
        }
        int tt=n-t;
        int flag=0;
        REP(i,1<<tt){
            LL sum=0;
            REP(j,tt){
                if(i&(1<<j))
                    sum+=num[t+j];
            }
            if(sum>m)continue;
            if(h1.find(m-sum)){
                flag=1;
                break;
            }
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}
时间: 2025-01-15 05:41:14

ACDREAM 1726 A Math game(折半枚举+hash)的相关文章

ACDream 1726 A Math game (折半查找)

A Math game Time Limit: 2000/1000MS (Java/Others) Memory Limit: 256000/128000KB (Java/Others) Submit Statistic Next Problem Problem Description Recently, Losanto find an interesting Math game. The rule is simple: Tell you a number H, and you can choo

acdream 1726 A Math game (部分和问题 DFS剪枝)

A Math game Time Limit: 2000/1000MS (Java/Others) Memory Limit: 256000/128000KB (Java/Others) Problem Description Recently, Losanto find an interesting Math game. The rule is simple: Tell you a numberH, and you can choose some numbers from a set {a[1

ACdream 1726 A Math game (dfs+二分)

http://acdream.info/problem?pid=1726 官方题解:http://acdream.info/topic?tid=4246 求n个数里面能不能选一些数出来让它们的和等于k. 因为k很大,不能用背包,但是n很小,最大为40,所以拆成了2部分,之后最大为2^20次方<1050000;每次枚举前一半的和,然后用数组存储,然后得到一个总和减去后一半的差用二分查找. 1 #include<cstdio> 2 #include<cstring> 3 #inc

ACdream 1726 A Math game

深搜.不过有一个强大的剪枝.就是假设之后的全部用上都不能达到H,则return. if (A[n]-A[x-1]+summ< H) return; //A[n]表示前nx项和 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 50; long long a[maxn], A[maxn]; int flag, n; long lon

poj1840 Eqs(hash+折半枚举)

Description Consider equations having the following form: a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 The coefficients are given integers from the interval [-50,50]. It is consider a solution a system (x1, x2, x3, x4, x5) that verifies the equation, xi∈[-50,

Eqs 折半枚举+二分查找 大水题

Eqs 题目抽象:a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 (*),给出a1,a2,a3,a4,a5.    ai属于[-50,50]. 求有多少序列   x1,x2,x3,x4,x5 ,xi属于 [-50,50]-{0}. 思路:折半枚举+二分查找 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #inclu

折半枚举——poj3977

暴力搜索超时,但是折半后两部分状态支持合并的情况,可用折半枚举算法 poj3977 给一个序列a[],从里面找到k个数,使其和的绝对值最小 经典折半枚举法+二分解决,对于前一半数开一个map,map[sum]里存下凑出当前sum的最小元素个数 枚举后面一半的所有情况,然后lower_bound去找map里最接近-sum的元素,由于要求输出sum最小并且num也尽量小的答案,所以用pair来存答案 #include<iostream> #include<algorithm> #inc

Educational Codeforces Round 76 F 折半枚举

Educational Codeforces Round 76 F 折半枚举 https://codeforces.com/contest/1257/problem/F 题意: 数组a,找到一个x使得a中每一个元素异或x后"二进制中1的个数"相同. 数组长度100,数字大小2^30. 思路: 折半枚举答案X,如分为X前15位和后15位.之后我们再枚举期望的"相同个数"是多少,通过hash看看能不能满足就好了. 代码: #include <bits/stdc++

Load Balancing 折半枚举大法好啊

Load Balancing 给出每个学生的学分.   将学生按学分分成四组,使得sigma (sumi-n/4)最小.         算法:   折半枚举 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <string> 7 #include <