JZOJ1241. Number

来源:互联网 发布:win10网络受限怎么办 编辑:程序博客网 时间:2024/06/05 20:27

题目

Description

有N(2<=N<=15)个数A1,A2,….,An-1,An,如果在这N个数中,有且仅有一个数能整除m,那么整数m就是一个幸运数,你的任务就是在给定A1,A2,….,An-1,An的情况下,求出第k小的幸运数。

Input

第一行为一整数数N,K(2<=N<=15,1<=K<=2^31-1),意义如上述。
接下来一行有N个整数,A1,A2,….,An-1,An,这N个整数均不超过2^31-1。

Output

输出一行,仅包含一个整数ans,表示第K小的幸运数。答案保证不超过10^15。

Sample Input

输入1:

2 4

2 3

输入2:

2 100

125 32767

Sample Output

输出1:

8

输出2:

12500

Hint

对于50%的数据,N<=5,ANS<=100000
对于80%的数据,N<=10,ANS<=10^15
对于100%的数据,N<=15,ANS<=10^15

分析

观察数据范围:
对于50%的数据是很简单的,只需要暴力。

而要通过后面的数据就有点小困难。

题解

很容易想到最后的答案肯定是A[]中间的某个数乘上一个整数。

看到K怎么大枚举每一个数很显然是不现实的。

我们考虑一下,可不可以把问题转换一下,
看一下可不可以变成一个判断问题。

  • 看到K这么大,想到用二分。

现在问题就变成了求在区间[1..mid]有多少个符合条件的数。

  • 有关整数倍数的问题很容易想到容斥原理。

code

#include <cstdio>#include <algorithm>#include <cstring>#include <string.h>#include <cmath>#include <stdlib.h>#include <math.h>#define ll long long using namespace std;ll a[20],l,r,ans,k,mid;int n,m;ll gcd(ll x,ll y){    if(x%y==0)return y;else return gcd(y,x%y);}void bfs(int x,ll sum,int deep){    if(sum>mid)return;    if(deep%2)ans+=floor(mid/sum)*deep;else ans-=floor(mid/sum)*deep;    for(int i=x+1;i<=n;i++)        bfs(i,sum/gcd(sum,a[i])*a[i],deep+1);}int main(){    scanf("%d%lld",&n,&k);    for(int i=1;i<=n;i++)        scanf("%lld",&a[i]);    l=1;    r=1000000000000000;    while(l<r)    {        mid=(l+r)/2;        ans=0;        for(int i=1;i<=n;i++)            bfs(i,a[i],1);        if(ans<k)l=mid+1;else r=mid;    }    printf("%lld\n",l);}
1 0