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; }
个性签名:时间会解决一切