题目描述:

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(折半枚举二分)的更多相关文章

  1. Codeforces 912 E.Prime Gift (折半枚举、二分)

    题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e ...

  2. Codeforces 912E - Prime Gift

    912E - Prime Gift 思路: 折半枚举+二分check 将素数分成两个集合(最好按奇偶位置来,保证两集合个数相近),这样每个集合枚举出来的小于1e18的积个数小于1e6. 然后二分答案, ...

  3. CF912E Prime Gift题解(搜索+二分答案)

    CF912E Prime Gift题解(搜索+二分答案) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1314956 洛谷题目链接 $     $ CF题目 ...

  4. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  5. Codeforces 912E Prime Gift ( 二分 && 折半枚举 && 双指针技巧)

    题意 : 给你 N ( 1 ≤ N ≤ 16 ) 个质数,然后问你由这些质数作为因子的数 ( 此数不超 10^18 ) & ( 不一定需要其因子包含所给的所有质数 ) 的第 k 个是什么 分析 ...

  6. Codeforces 912E Prime Gift(预处理 + 双指针 + 二分答案)

    题目链接 Prime Gift 题意  给定一个素数集合,求第k小的数,满足这个数的所有质因子集合为给定的集合的子集. 保证答案不超过$10^{18}$ 考虑二分答案. 根据折半的思想,首先我们把这个 ...

  7. POJ 3977 Subset(折半枚举+二分)

    SubsetTime Limit: 30000MS        Memory Limit: 65536KTotal Submissions: 6754        Accepted: 1277 D ...

  8. Subset---poj3977(折半枚举+二分查找)

    题目链接:http://poj.org/problem?id=3977 给你n个数,找到一个子集,使得这个子集的和的绝对值是最小的,如果有多种情况,输出子集个数最少的: n<=35,|a[i]| ...

  9. Codeforces 626E Simple Skewness(暴力枚举+二分)

    E. Simple Skewness time limit per test:3 seconds memory limit per test:256 megabytes input:standard ...

随机推荐

  1. 展示时测试Markdown渲染

    \begin{equation} %公式 Speedup_{overall} = \frac{1}{{(1-Fraction_{partitioned})} +\frac{Fraction_{part ...

  2. 【Gamma阶段】第九次Scrum Meeting

    冰多多团队-Gamma阶段第九次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 卓培锦 美化前端及编辑器界面,编辑器风格切换(添加夜间模式) UI界面手势切换 牛雅哲 添加scp工具,添加 ...

  3. ShowDoc 软件开发团队接口文档管理利器

    ShowDoc是一个非常适合IT团队的在线API文档.技术文档工具.你可以使用Showdoc来编写在线API文档.技术文档.数据字典.在线手册. 这里介绍 Showdoc 这款开源(免费)文档管理系统 ...

  4. MPI linux Ubuntu cluster 集群

    在局域网内安装mpi,并进行并行计算.MPICH3. 下载源码: wget http://www.mpich.org/static/downloads/3.3.1/mpich-3.3.1.tar.gz ...

  5. Chartjs 简单使用 ------ 制作sin cos 折线图

    Chart.js 一款简单干净的图表工具,基于html5 的Javascript. 可以用来制做条形,扇形,折线,混合等等的强大工具 图表要放在html 的  cancas  标签中 <canv ...

  6. Isilon的WebUI上指定跨时区时间的小问题

    Isilon的WebUI的界面长这样: 假设我们在中国,也就是GMT+8的时区,我们想修改一个远在美国的Isilon cluster的时间. 你会发现,界面上用于指定时间的地方应该填写的不是下面选择的 ...

  7. CentOS7使用tar.gz包安装MySql的踩坑之旅

    由于客户的CentOS服务器没有安装yum工具,只能通过下载tar.gz包安装mysql,于是跟着万能的百度开启了漫漫踩坑之旅: 1.下载mysql-5.6.33-linux-glibc2.5-x86 ...

  8. Lua函数声明与调用

    lua编程中,我们经常也会遇到函数的声明定义和调用. [1]lua中函数定义与调用的方法 lua有两种函数定义和调用的方法(本质都是用属性,方式不同而已): (1)点号形式 (2)冒号形式 两种方法的 ...

  9. 洛谷P5017:摆渡车——题解

    https://www.luogu.org/problem/P5017 参考:https://www.luogu.org/blog/ztyluogucpp/solution-p5017 我想我大概是废 ...

  10. Direct Buffer介绍

    Direct Buffer 前言 上篇文章Buffer末尾中谈到堆内Buffer(Heap Buffer)和直接Buffer(Direct Buffer)的概念,但是却一笔带过,并未涉及其细节,这篇文 ...