题目大意
有N(2<=N<=15)N(2<=N<=15)N(2<=N<=15)个数A1,A2,....,AnA_1,A_2,....,A_nA1,A2,....,An−_-−1_11,AnA_nAn,如果在这NNN个数中,有且仅有一个数能整除mmm,那么整数mmm就是一个幸运数,你的任务就是在给定A1,A2,....,AnA_1,A_2,....,A_nA1,A2,....,An−_-−1_11,AnA_nAn的情况下,求出第kkk小的幸运数。
题目解析
二分答案,算出111~midmidmid区间内有多少个数符合条件,这个可以暴力枚举选哪些数,算出lcmlcmlcm,再用容斥原理做。要注意的是开longlonglong longlonglong而且lcmlcmlcm可能会超出longlonglong longlonglong范围。
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL n,k,b=1e16;
LL a[20];
bool flag[20];
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}
LL lcm(LL x,LL y) {return x*y/gcd(x,y);}
struct A
{
LL num,p;
}f[1000005];
int cnt;
void dfs(int lev)
{
if(lev>n)
{
bool ff=1;
LL p=1,num=0;
for(int i=1;i<=n;i++)
if(flag[i])
{
num++,p=lcm(p,a[i]);
if(p>1e15)
{
ff=0;
break;
}
}
if(ff) f[++cnt].num=num,f[cnt].p=p;
return;
}
dfs(lev+1);
flag[lev]=1;
dfs(lev+1);
flag[lev]=0;
}
bool check(LL x)
{
LL ans=0;
for(int i=1;i<=cnt;i++)
if(f[i].num%2==1) ans+=floor(x/f[i].p)*f[i].num;
else if(f[i].num%2==0) ans-=floor(x/f[i].p)*f[i].num;
if(ans>=k) return true;
else return false;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
dfs(1);
LL l=0,r=1e15,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) r=mid-1,b=min(b,mid);
else l=mid+1;
}
while(check(b)) b--;
cout<<b+1;
}