2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem——哈希表&&二进制枚举

题意

有长度为 $n$($1\leq n\leq 36$)的数列,给出 $s$,求和为 $s$ 的子集,保证子集存在且唯一。

分析

答案肯定是来自左右半边两部分组成的。

如果我们用哈希表存一半,计算另一半的值 $v$,再在哈希表中查找 $s-v$,这样规模从 $2^{36}$ 降至 $2^{18}$,其实就是折半搜索。

#include<bits/stdc++.h>
using namespace std;

typedef  long long ll;
ll n, s, a[40];
ll A[1 << 20];
unordered_map<ll, int>mp;

int main()
{
    scanf("%lld%lld", &n, &s);
    for(int i = 0;i < n;i++)  scanf("%lld", &a[i]);

    int l = n / 2;  //左边的长度
    for(int i = 0;i < (1 << l);i++)
        for(int j = 0;j < l;j++)
        {
            if((i >> j) & 1)
                A[i] += a[j];
        }

    int r = n - l;  //右边的长度
    for(int i = 0;i < (1 << r);i++)
    {
        ll tmp = 0;
        for(int j = 0;j < r;j++)
        {
            if((i >> j) & 1)
                tmp += a[j+l];
        }
        mp[tmp] = i;
    }

    //查找
    for(int i = 0;i < (1 << l);i++)
    {
        ll cha = s - A[i];
        if(mp.count(cha))
        {
            for(int j = 0;j < l;j++)
            {
                if((i >> j) & 1)  printf("1");
                else printf("0");
            }
            for(int j = 0;j < r;j++)
            {
                if((mp[cha] >> j) & 1)  printf("1");
                else  printf("0");
            }
            printf("\n");
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lfri/p/11360824.html