CF912E Prime Gift

题目大意

给定一个大小为 n 的素数集合
求出分解后只含这些质数因子的第 k 小整数
题目链接

题解

在n这么小的情况下,肯定优先考虑暴搜
可是爆搜显然空间开不下,
那我们想想来如何优化这个暴搜,meet-in-the-middle!!!
把整个素数集合分成两半,分别记录下每一部分元素可以组合出的所有小于 1E18 的数
然后再二分答案,每次check过程中合并这两个集合中的元素,找到比 mid 小的个数就行了

代码

#include<bits/stdc++.h>
using namespace std;
#define re register
#define int long long
#define in inline
#define get getchar()
#define pb push_back
in int read()
{
	int t=0; char ch=get;
	while( ch<'0' || ch>'9') ch=get;
	while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
	return t;
}
const int maxn=1e18;
const int _=1e3+5;
vector<int> v[3];
int n,p[_],sums=0;
in void dfs(int k,int i,int mul)
{
	if(i>n)
	{
		v[k].pb(mul);
		return ;
	}
	for(re int qwe=1;;qwe*=p[i])
	{
		dfs(k,i+2,mul*qwe);
		if(mul*qwe>maxn/p[i])return;
	}
}

signed main()
{
	n=read();
	v[1].pb(0),	v[2].pb(0);
	for(re int i=1;i<=n;i++)
		p[i]=read();
	int k=read();
	dfs(1,1,1);dfs(2,2,1);
	sort(&v[1][1],&v[1][v[1].size()]);
	sort(&v[2][1],&v[2][v[2].size()]);
	int l=0,r=maxn,ans=0,len1=v[1].size()-1,len2=v[2].size()-1;
	while(l<=r)
	{
		int mid=l+r>>1,res=0;
		for(re int i=1,j=len2;j>=1&&i<=len1;res+=j,i++){
			while(j&&v[2][j]>mid/v[1][i]) j--;
		}
		if(res<k) l=mid+1;
		else r=mid-1,ans=mid;
	}
	cout<<ans<<endl;
}

posted @ 2019-10-26 11:20  yzhx  阅读(115)  评论(0编辑  收藏  举报