题目描述:

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. C# byte数组与16进制间的相互转换

      1.byte数组转16进制字符串 /// <summary> /// 将一个byte数组转换成16进制字符串 /// </summary> /// <param na ...

  2. Hyperledger Fabric 1.4 快速环境搭建

    自己的硕士研究方向和区块链有关,工程上一直以IBM的Hyperledger Fabric为基础进行开发,对该项目关注也有两年了.目前迎来了Hyperledger Fabric v1.4,这也是Fabr ...

  3. flink安装启动(docker)

    参考https://hub.docker.com/_/flink/ 相关端口The Web Client is on port 8081JobManager RPC port 6123TaskMana ...

  4. Ribbon核心组件IRule及配置指定的负载均衡算法

    Ribbon在工作时分为两步: 第一步:先选择 EurekaServer,它优先选择在同一个区域内负载较少的Server: 第二步:再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地 ...

  5. HTTP漫谈

    一.说明 1.1 当前背景说明 很多web的书包括web安全的书都会有一章介绍http协议,我就总恶意揣测作者是在凑字数,一般都直接跳过去. 相比TCP/IP这种各字段基于数值代号的协议,http这种 ...

  6. 使用benchmarkSQL测试数据库的TPCC

    压力测试是指在MySQL上线前,需要进行大量的压力测试,从而达到交付的标准.压力测试不仅可以测试MySQL服务的稳定性,还可以测试出MySQL和系统的瓶颈. TPCC测试:Transaction Pr ...

  7. C语言知识点总结篇

    Debug和Release版本比较 Debug附加了许多调试信息,主要用于调试,故文件大: Release是经过优化后的版本,去掉了调试信息,代码进行了优化,故文件较小,且编译速度快过Debug,用于 ...

  8. HTML5 Canvas实战之刮奖效果【转】

    开源项目地址:https://github.com/artwl/Lottery 作者博客地址:http://www.cnblogs.com/jscode/p/3580878.html 谢谢浏览!

  9. js遍历数组和数组对象

    <script> //----------------for用来遍历数组对象-- var i,myArr = [1,2,3]; for (var i = 0; i < myArr.l ...

  10. mvn clean -U -e -B -X的作用 查看详细出错信息

    https://blog.csdn.net/u014515854/article/details/79820497     在持续集成服务器上使用怎样的 mvn 命令集成项目,这个问题乍一看答案很显然 ...