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;
}
嗯,就这样了...