给你一个长度为n的集合,如果一个数满足它所有的质因子都在这个集合中,那么这个数就是合法的
求第k小的合法数(1<=n<=16),答案不会超过1e18
思路:
将n个数对半拆成两个集合,每个集合元素不会超过8个,对于每个集合爆搜出1e18范围内所有的合法数
之后查询第k大时二分答案ans,可以用双指针求出当前ans是第几个合法数
#include<algorithm>
#include<stdio.h>
#include<iostream>
using namespace std;
#define LL long long
LL a[10000005], b[10000005], A[22], B[22], k;
int c, d, sa, sb, n;
LL Jud(LL x)
{
LL res;
int p, i;
p = d, res = 0;
for(i=1;i<=c;i++)
{
if(a[i]>x)
break;
while(b[p]>x/a[i] && p>=1)
p--;
res += p;
}
return res;
}
void Sech1(int id, LL now)
{
LL ans = 1;
if(id==sa+1)
{
a[++c] = now;
return;
}
while(now<=1e18/ans)
{
Sech1(id+1, now*ans);
if(ans>1e18/A[id])
break;
ans *= A[id];
}
}
void Sech2(int id, LL now)
{
LL ans = 1;
if(id==sb+1)
{
b[++d] = now;
return;
}
while(now<=1e18/ans)
{
Sech2(id+1, now*ans);
if(ans>1e18/B[id])
break;
ans *= B[id];
}
}
int main(void)
{
LL l, r, mid;
int n, x, i;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
scanf("%d", &x);
if(i%2==1)
A[++sa] = x;
else
B[++sb] = x;
}
scanf("%lld", &k);
Sech1(1, 1);
Sech2(1, 1);
sort(a+1, a+c+1);
sort(b+1, b+d+1);
l = 1, r = 1e18;
while(l<r)
{
mid = (l+r)/2;
if(Jud(mid)>=k)
r = mid;
else
l = mid+1;
}
printf("%lld\n", r);
return 0;
}