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;
}


 

你可能感兴趣的:(ACDREAM 1726 A Math game(折半枚举+hash))