Codeforces H. Prime Gift(折半枚举二分)
题目描述:
Prime Gift
time limit per test
3.5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Opposite to Grisha's nice behavior, Oleg, though he has an entire year at his disposal, didn't manage to learn how to solve number theory problems in the past year. That's why instead of Ded Moroz he was visited by his teammate Andrew, who solemnly presented him with a set of n distinct prime numbers alongside with a simple task: Oleg is to find the k-th smallest integer, such that all its prime divisors are in this set.
Input
The first line contains a single integer n (1 ≤ n ≤ 16).
The next line lists n distinct prime numbers p1, p2, ..., pn (2 ≤ pi ≤ 100) in ascending order.
The last line gives a single integer k (1 ≤ k). It is guaranteed that the k-th smallest integer such that all its prime divisors are in this set does not exceed 1018.
Output
Print a single line featuring the k-th smallest integer. It's guaranteed that the answer doesn't exceed 1018.
Examples
input
3
2 3 5
7
output
8
input
5
3 7 11 13 31
17
output
93
Note
The list of numbers with all prime divisors inside {2, 3, 5} begins as follows:
(1, 2, 3, 4, 5, 6, 8, ...)
The seventh number in this list (1-indexed) is eight.
思路:
刚开始完全处于懵逼状->这样o((⊙﹏⊙))o咱啥也不会,啥思路也没有。这是什么题,给你一个装着最多十六个素数的集合S,算出第k个数,使得这个数的全部素因子在这个集合中。第一个想法是暴力枚举,枚举出由这些数构造出的所有小于等于\(10^{18}\)的数。可第一步咋构造咱都不会(只是我不会)。后来才知道可以用dfs暴力构造集合G,像下面这样:
void dfs(int l,int r,long long val)//l,r指给的素数集合区间左右端点
{
num.push_back(val);//num存构造的数
for(int i = l;i<=r;i++)
{
if(val<=INF/a[i])//INF就是10^18
{
dfs(i,r,val*[i],id);//不断选择素因子相乘
}
}
}
dfs(1,a.size()-1,1);
还可以这样
void dfs(int idx, int64_t cur)
{
if (idx == s.size()) {//s是存的素因子的集合
gs.push_back(cur);//gs是构造出的数
return;
}
if (s[idx] <= inf / cur)
dfs(idx, cur * s[idx]);
dfs(idx + 1, cur);
}
于是集合G构造好了,但是肯定超时。于是考虑折半,怎么折。把素因子集合的奇数下标元素分一组记为S1,偶数下标分一组记为S2,再分别构造出G1,G2,这样做可以减小枚举的范围(如果不分的话将会枚举一个很庞大的范围)。然后呢?我们从1到INF中二分寻找数x,使得x是素因子构造的集合中的第k个数,就找到了题目中要求的x。
那我们怎么判断一个数是原集合G中的第几个数呢?要知道,新构造出的G1,G2只是由原来的S的一半构造出来的,还缺了将两个集合“乘起来”才能得到的数。比如S={2,3,5},S1={2,5},S2={3},G1={2,4,5,8,10,...},G2={3,9,27,81,...}。却了{6,18,...},等等有两个集合"相乘"得到的数。那还怎么知道数x是G的第几个数呢?这里用到了巧妙的思想,就是把集合排好序后从一个集合G1的最大元素开始枚举G1[i],看第二个集合G2中有多少数能够小于等于\(\frac{x}{G1[i]}\),这一个操作实际上已经是在把两个集合“相乘”体现出来了,也就是看数x前面有多少个小于等于x的数,因为前面说了G就是G1"乘"G2的结果。所以最后得到的就是x本身在G中的位置。
注意的是一个技巧,在看G2中有多少个数小于等于\(\frac{x}{G1[i]}\)时由于G1[i]是从小到大的,那么上一次判断的终止G2[j]一定小于\(\frac{x}{G1[i]}\),因此G2不必每次都从0开始判断,直接接着上一次判断的结果继续累计就可以了。
还有就是二分答案的细节返回l(左端点),当然不同的写法返回的不一定是l。
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#define max_n 20
#define INF 1e18
using namespace std;
int n;
int k;
int fac[max_n];
vector<long long> num[2];
vector<int> a[2];
void dfs(int l,int r,long long val,int id)
{
num[id].push_back(val);
for(int i = l;i<=r;i++)
{
if(val<=INF/a[id][i])
{
dfs(i,r,val*a[id][i],id);
}
}
}
int check(long long x)
{
long long res = 0;
long long j = 0;
for(int i = num[0].size()-1;i>=0;i--)
{
while(j<num[1].size()&&num[1][j]<=x/num[0][i]) j++;
res += j;
}
return res;
}
int main()
{
cin >> n;
for(int i = 0;i<n;i++)
{
int tmp;
cin >> tmp;
a[i&1].push_back(tmp);
}
cin >> k;
dfs(0,a[0].size()-1,1,0);
sort(num[0].begin(),num[0].end());
dfs(0,a[1].size()-1,1,1);
sort(num[1].begin(),num[1].end());
/*for(int i = 0;i<num[0].size();i++)
{
cout << num[0][i] << " ";
}
cout << endl;
for(int i = 0;i<num[1].size();i++)
{
cout << num[1][i] << " ";
}
cout << endl;*/
long long l = 0;
long long r = INF;
long long mid;
while(l<=r)
{
mid = (l+r)>>1;
long long ord = check(mid);
if(ord<k)
{
l = mid+1;
}
else
{
r = mid-1;
}
}
cout << l << endl;
return 0;
}
参考文章:
Wisdom+.+,912E - Prime Gift,https://www.cnblogs.com/widsom/p/8352859.html
SiuGinHung,Codeforces 912E - Prime Gift,https://www.cnblogs.com/siuginhung/p/8232064.html
Codeforces H. Prime Gift(折半枚举二分)的更多相关文章
- Codeforces 912 E.Prime Gift (折半枚举、二分)
题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e ...
- Codeforces 912E - Prime Gift
912E - Prime Gift 思路: 折半枚举+二分check 将素数分成两个集合(最好按奇偶位置来,保证两集合个数相近),这样每个集合枚举出来的小于1e18的积个数小于1e6. 然后二分答案, ...
- CF912E Prime Gift题解(搜索+二分答案)
CF912E Prime Gift题解(搜索+二分答案) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1314956 洛谷题目链接 $ $ CF题目 ...
- CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
1514: Packs Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 61 Solved: 4[Submit][Status][Web Board] ...
- Codeforces 912E Prime Gift ( 二分 && 折半枚举 && 双指针技巧)
题意 : 给你 N ( 1 ≤ N ≤ 16 ) 个质数,然后问你由这些质数作为因子的数 ( 此数不超 10^18 ) & ( 不一定需要其因子包含所给的所有质数 ) 的第 k 个是什么 分析 ...
- Codeforces 912E Prime Gift(预处理 + 双指针 + 二分答案)
题目链接 Prime Gift 题意 给定一个素数集合,求第k小的数,满足这个数的所有质因子集合为给定的集合的子集. 保证答案不超过$10^{18}$ 考虑二分答案. 根据折半的思想,首先我们把这个 ...
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- Subset---poj3977(折半枚举+二分查找)
题目链接:http://poj.org/problem?id=3977 给你n个数,找到一个子集,使得这个子集的和的绝对值是最小的,如果有多种情况,输出子集个数最少的: n<=35,|a[i]| ...
- Codeforces 626E Simple Skewness(暴力枚举+二分)
E. Simple Skewness time limit per test:3 seconds memory limit per test:256 megabytes input:standard ...
随机推荐
- 华为鸿蒙OS发布!方舟支持混合编译,终将可替换安卓?
前言 有关于鸿蒙的消息之前也有说过,就在昨天下午,华为举行了2019开发大会,正式推出了鸿蒙os系统(Harmony).其相关负责人表示,也是基于微软内核的全场景分布式OS 鸿蒙凭借微内核的优势, ...
- Spring Boot进阶系列三
Thymeleaf是官方推荐的显示引擎,这篇文章主要介绍怎么让spring boot整合Thymeleaf. 它是一个适用于Web和独立环境的现代服务器端Java模板引擎. Thymeleaf的主要 ...
- [HeadFrist-HTMLCSS学习笔记]第二章深入了解超文本:认识HTML中的“HT”
[HeadFrist-HTMLCSS学习笔记]第二章深入了解超文本:认识HTML中的"HT" 敲黑板!!! 创建HTML超链接 <a>链接文本(此处会有下划线,可以单击 ...
- 微信小程序云开发不完全指北
微信小程序云开发不完全指北 首先必须说明云开发的"云"并不是类似云玩家里的云的意思,而是微信小程序真的提供了云开发的接口以及一个简单的提供存储.数据库服务的虚拟后台(对于一些轻量小 ...
- jQuery学习路线。
通过jQuery思维导图,来进行计划的温习/掌握 jQuery技能. 通过思维导图的思路学习,是很好的学习方法之一,思路清晰.跟上环节,易于贯通,重要的是少走弯路. 这里一共有6张图,第1张是大纲路线 ...
- 【转】Selenium 报错:Element is not clickable at point的解决办法
天一同学在写Selenium Java脚本时遇到一个问题,登录进入系统之后,要点击左侧的一个菜单,但是执行到该语句时报下面的错误: Firefox中报错如下:org.openqa.selenium.E ...
- C语言注释风格
注释风格 一.前言 注释是源码程序中非常重要的一部分,一般情况下,源程序有效注释量必须在20%以上. 注释的原则是有助于对程序的阅读理解,所以注释语言必须准确.易懂.简洁,注释不宜太多也不能太少,注释 ...
- Java 加载动态库 dll 文件
不知道具体原理,但是,加载 dll 文件时,带路径或者更改 dll 文件的名字,都会报错.虽然库记载成功了,但是处女座认为这不可接受.于是有了这个解决方案. 在根目录为库创建软连接,然后使用 syst ...
- 基于已有集群动态发现方式部署 Etcd 集群
etcd提供了多种部署集群的方式,在「通过静态发现方式部署etcd集群」 一文中我们介绍了如何通过静态发现方式部署集群. 不过很多时候,你只知道你要搭建一个多大(包含多少节点)的集群,但是并不能事先知 ...
- .NET Core解析DNS域名或主机名的方法
在.NET Core中我们可以用System.Net.Dns类来解析域名或主机名的IP地址,我们新建一个.NET Core控制台项目,写入下面代码: using System; using Syste ...