题目描述:

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. listings技巧

    1. \lstdefinestyle 参考 https://blog.csdn.net/ProgramChangesWorld/article/details/52142313 我们在使用listin ...

  2. Spring Cloud Greenwich.SR4 发布了,跟不上了……

    前几天 Spring Cloud Greenwich.SR4 发布了: https://spring.io/blog/2019/11/19/spring-cloud-greenwich-sr4-rel ...

  3. 转 史上最详细的Hadoop环境搭建

    GitChat 作者:鸣宇淳 原文:史上最详细的Hadoop环境搭建 关注公众号:GitChat 技术杂谈,一本正经的讲技术 [不要错过文末活动哦] 前言 Hadoop在大数据技术体系中的地位至关重要 ...

  4. 微服务异步架构---MQ之RocketMQ

    “我们大家都知道把一个微服务架构变成一个异步架构只需要加一个MQ,现在市面上有很多MQ的开源框架.到底选择哪一个MQ的开源框架才合适呢?” 一.什么是MQ?MQ的原理是什么? MQ就是消息队列,是Me ...

  5. 【操作系统之三】Linux下进程间通信-IPC(Inter-Process Communication)

    管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信:信号(Sign ...

  6. mysql 添加注释

    给表添加注释:  alter table m_tb100_disabledsoldier comment '残疾士兵';   给表中的字段添加注释alter table m_tb100_disable ...

  7. zooKeeper使用记录

    背景:记录zooKeeper使用过程中遇到的问题. 在删除zooKeeper相关节点的时候需要进行权限的认证,下面的连接讲的还是很详细的 zookeeper的ACL权限控制

  8. Java中的数据类型与运算符

    一.变量的命名 (1)什么是变量:变量是java中存储数据的空间. (2)变量命名的规则:由:数(数字),字(字母),下(下划线),美(美元符号),人(人名币符号)组成的标识符.注:数字不能作为首字母 ...

  9. git cherry-pick 命令,解决冲突后没有 commit 变更,再次pull 时出错

    Git : You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists). 解决方法:(1)使用git status 命令查看当前 ...

  10. intellij idea快速通过mapper跳转到xml文件

    安装完之后重启idea即可!