CF912E Prime Gift 数学

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

Copy

32 3 57

Output

Copy

8

Input

Copy

53 7 11 13 3117

Output

Copy

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.

首先在1e18的范围内,那么质数的个数最多只有16个,你可以将这16个列出来然后相乘,看看多大;

那么我们分开算;

不妨将奇数位置的dfs和偶数位置的分别dfs;

分别算出包含这些因子的所有可能值,如果对数组开多大不确定,用 vector.push_back就好;

那么我们要求第k大,考虑二分答案;

那么对于我们之前求出的那两个集合,我们用 two-pointer 来扫一遍确定当前答案是第几个;

然后调整上下界即可;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
#include<ctime>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
//#include<cctype>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 300005
#define inf 0x3f3f3f3f
//#define INF 1e18
#define rdint(x) scanf("%d",&x)
#define rdllt(x) scanf("%lld",&x)
#define rdult(x) scanf("%lu",&x)
#define rdlf(x) scanf("%lf",&x)
#define rdstr(x) scanf("%s",x)
typedef long long  ll;
typedef unsigned long long ull;
typedef unsigned int U;
#define ms(x) memset((x),0,sizeof(x))
const long long int mod = 1e9 + 7;
#define Mod 1000000000
#define sq(x) (x)*(x)
#define eps 1e-3
typedef pair<int, int> pii;
#define pi acos(-1.0)
const int N = 1005;
#define REP(i,n) for(int i=0;i<(n);i++)
typedef pair<int, int> pii;
inline ll rd() {
	ll x = 0;
	char c = getchar();
	bool f = false;
	while (!isdigit(c)) {
		if (c == ‘-‘) f = true;
		c = getchar();
	}
	while (isdigit(c)) {
		x = (x << 1) + (x << 3) + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}

ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}
ll sqr(ll x) { return x * x; }

/*ll ans;
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) {
		x = 1; y = 0; return a;
	}
	ans = exgcd(b, a%b, x, y);
	ll t = x; x = y; y = t - a / b * y;
	return ans;
}
*/

int n;
int p[30]; ll k;
vector<ll>vc[2];
int tmp[30]; int cnt;

void dfs(int belong, ll val, int cur) {
	vc[belong].push_back(val);
	for (int i = cur; i <= cnt; i++) {
		if (1e18 / tmp[i] >= val) {
			dfs(belong, val*tmp[i], i);
		}
	}
}

ll sol(ll x) {
	ll res = 0;
	int j = 0;
	for (int i = vc[0].size() - 1; i >= 0; i--) {
		while (j < vc[1].size() && vc[1][j] <= x / vc[0][i])j++;// 双指针扫一遍
		res += j;
	}
	return res;
}

int main()
{
	//ios::sync_with_stdio(0);
	rdint(n);
	for (int i = 1; i <= n; i++)rdint(p[i]);
	rdllt(k);
	for (int i = 1; i <= n; i++)if (i & 1)tmp[++cnt] = p[i];
	dfs(0, 1, 1);
	cnt = 0;
	for (int i = 1; i <= n; i++)if (i % 2 == 0)tmp[++cnt] = p[i];
	dfs(1, 1, 1);
	sort(vc[0].begin(), vc[0].end());
	sort(vc[1].begin(), vc[1].end());
	ll l = 1, r = 1e18;
	while (l <= r) {
		ll mid = (l + r) / 2;
		if (sol(mid) >= k)r = mid - 1;
		else l = mid + 1;
	}
	cout << l << endl;
	return 0;
}

原文地址:https://www.cnblogs.com/zxyqzy/p/10125444.html

时间: 2024-10-08 21:05:30

CF912E Prime Gift 数学的相关文章

CF912E Prime Gift(Meeting In The Middle+Two pointers)

原题 挂个链接CodeForces 题目大意:给定k个质数,求出约数中只有由这几个数组合一下(可以多次用一个数)的第k个值 Solution 分析: 我们看到n是16,然后如果爆搜n/2是可以过的.所以考虑Meeting In The Middle 他让我们求第k个数,理所应当地想到二分答案. 然后我们先把所有的组合求出来,然后二分答案判断就好了. #include<stdio.h> #include<stdlib.h> #include<string.h> #incl

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

题目链接 Prime Gift 题意  给定一个素数集合,求第k小的数,满足这个数的所有质因子集合为给定的集合的子集. 保证答案不超过$10^{18}$ 考虑二分答案. 根据折半的思想,首先我们把这个集合的数分成两组. 然后分别生成这两组质数所能表示出的正整数的集合. 然后把这个集合sort一下,我们得到了两个有序的数列. 在计算小于等于某个数$x$的符合题目条件的数的时候,我们枚举第一个集合中的数, 用双指针定位和当前枚举到的数乘积恰好小于等于$x$的位置. 然后累加. 这里有一个细节,我们要

912E - Prime Gift

912E - Prime Gift 思路: 折半枚举+二分check 将素数分成两个集合(最好按奇偶位置来,保证两集合个数相近),这样每个集合枚举出来的小于1e18的积个数小于1e6. 然后二分答案,check时枚举其中一个集合,然后找到另外一个集合小于mid/该元素的元素有多少个,这里用到一个双指针的技巧将复杂度降到O(n):一个集合从大到小枚举,那么mid/该元素就会逐渐变大,那么直接从上次找到的位置往后找就可以了,因为答案肯定在后面. 代码: #include<bits/stdc++.h>

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

题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e18) 题解: 如果暴力dfs的话肯定超时间,其实给的n数据范围最大是16是一个很奇妙的数(一般折半枚举基本上是这样的数据范围@.@-).所以想到折半枚举,把所有的质数分成两份求出每份中所有小于1e18的满足条件的数.然后二分答案,写cheak函数时遍历第一个集合,对第二个集合二分(折半枚举基本上这个套路).

HDU 6623&quot;Minimal Power of Prime&quot;(数学)

传送门 •题意 给你一个大于 1 的正整数 n: 它可以分解成不同的质因子的幂的乘积的形式,问这些质因子的幂中,最小的幂是多少. •题解 定义 $ans$ 表示最终答案: ①如果 $ans \ge 5$: 那么,肯定有 $n=p^{ans}\ ,\ p \le \sqrt[{ans}]{n}$,也就是说 $\ p \le 10^{\frac{18}{5}}$: 所以,我们可以提前预处理出 $[1,10000]$ 的素数表 •Code 1 #include<bits/stdc++.h> 2 us

Prime Gift CodeForces - 912E (中途相遇)

链接 大意:求素因子只含给定素数的第k大数 先二分答案转为判定x是第几大, 然后分两块合并即可, 按奇偶分块可以优化一下常数 #include <iostream> #include <algorithm> #include <cstdio> #include <vector> #define PER(i,a,n) for(int i=n;i>=a;--i) #define REP(i,a,n) for(int i=a;i<=n;++i) #de

Codeforces Round #456 (Div. 2)

C. Perun, Ult! 分析 首先对于每个敌人单独预处理时间线(即在什么时候可以杀死这个敌人,什么时候杀不死了),然后通过一个总时间线去更新答案. code #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; map<long long, int> add, erase; set<long long> timeline; vector<pair<long long,

hdu 5171 GTY&#39;s birthday gift(数学,矩阵快速幂)

题意: 开始时集合中有n个数. 现在要进行k次操作. 每次操作:从集合中挑最大的两个数a,b进行相加,得到的数添加进集合中. 以此反复k次. 问最后集合中所有数的和是多少. (2≤n≤100000,1≤k≤1000000000) 思路: 写出来发现是要求Fibonaci的前n个数的和. Fibonaci是用矩阵快速幂求的,这个也可以. [Sn,Fn,Fn-1]=[某个矩阵]*[Sn-1,Fn-1,Fn-2] [S2,F2,F1]=[2,1,1] 然后写,,, 这个代码有些繁琐,应该把矩阵操作单独

(数学+尺取法)2739 - Sum of Consecutive Prime Numbers

原题链接:http://poj.org/problem?id=2739 题意:问一个数有几种方法用连续的素数和表示. 分析:其实就是很简单,先打表,然后对prime数组跑一波尺取法,如果==n就ans++. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include &