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 <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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值