JZOJ1241. Number

题目

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 
#include 
#include 
#include 
#include 
#include 
#include 
#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(l2;
        ans=0;
        for(int i=1;i<=n;i++)
            bfs(i,a[i],1);
        if(ans1;else r=mid;
    }
    printf("%lld\n",l);
}

你可能感兴趣的:(题解,容斥原理)