2019牛客暑期多校训练营(第九场)D-Knapsack Cryptosystem(思维+子集和)
2024-09-08 02:26:55
>传送门<
题意:给你一个有n个元素的数组,一个sum,让你找到数组的子集使得子集元素和等于sum,保证只有一个解决方案。
(其中1≤n≤36,0≤ sum<9*1018,0<ai<2*1017)
思路:写这题的时候队友直接搜子集,然后我就满脸???236,老哥你确定不会爆?于是天真的我发现和背包不是很像么,然后就用背包写,写完后发现W是9*1018,此时我的内心对我自己也是???
所以暴搜肯定是不行的,有一个很巧妙的思路,就是将数组分成两个区域,18个元素我们完全可以暴力枚举子集,并放到set里,然后再对右区域枚举子集,O(1)检查sum - 子集和是否存在就行了,完美~
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll a[maxn];
set<ll> s;
map<ll, ll> mp; int main()
{
int n, p, q;
ll sum;
scanf("%d %lld", &n, &sum);
for(int i = 0; i < n; ++i) scanf("%lld", &a[i]);
p = n / 2; q = n - p;
//先枚举左区间
for(int i = 0; i < (1 << p); i++) {
ll tmp = 0;
for(int j = 0; j < p; j++) {
if(i & (1 << j))
tmp += a[j];
}
s.insert(tmp);
mp[tmp] = i; //记录状态
}
//枚举右区间
for(int i = 0; i < (1 << q); i++) {
ll ret = 0;
for(int j = 0; j < q; j++) {
if(i & (1 << j))
ret += a[p + j];
}
//找到答案了
if(s.find(sum - ret) != s.end()) {
ll x = mp[sum - ret];
for(int j = 0; j < p; ++j)
printf("%d", (bool)(x & (1 << j)));
for(int j = 0; j < q; ++j)
printf("%d", (bool)(i & (1 << j)));
printf("\n");
return 0;
}
}
return 0;
}
这题用到了这些知识点:子集的生成,set的用法,map的用法
最新文章
- Ubuntu14.04下安装docker
- POI格式化Cell样式
- HDU 2717 Catch That Cow --- BFS
- dede 忘记密码在数据库中修改方法
- Maven构建Web项目问题汇总
- hdu 5340 (manacher)
- JavaScript基础精讲
- jmeter学习记录--05--Beanshell2
- pc端手機端自適應佈局方案
- python-虚拟环境搭建
- php-memcache基本用法
- emmc基础技术8:操作模式2-device identification mode
- Git:一本书 + 一个站点,让你掌握 Git
- mac os 里的 JAVA_HOME
- 中介者模式(QQ聊天室我觉得是个很生动的例子简单易懂)
- Windows10怎么架设局域网DNS服务器?
- 转:Sql Server中清空所有数据表中的记录
- LINUX 高可用群集之 ~Corosync~
- 读书笔记 Week6 2018-4-12
- HZAU 1205 Sequence Number(双指针)
热门文章
- 原生redis命令
- 超有用的linux笔记
- Centos7 密钥对登陆(适用于群晖DSM)
- Java 使用拦截器无限转发/重定向无限循环/重定向次数过多报错(StackOverflowError) 解决方案
- 最新最简洁Spring Cloud Oauth2.0 Jwt 的Security方式
- 请求接口获取的json 字符串 前后不能有 双引号
- 行业动态 | 利用Cassandra数据库揭开家族祖先的秘密
- 关于postgresql中numeric和decimal的精度和标度问题
- 如何用Python中自带的Pandas和NumPy库进行数据清洗
- 微服务网关1-Spring Cloud Gateway简介