GalaxyOJ-788 (二分+容斥)

题目

Problem Description

现在有n个数a1,a2,…,an,如果一个正整数m可以被这n个数中的任意一个整除,则称m是一个Easy Number。现在给出n个数,求第k小的Easy Number。

Input

一行两个整数n和k。
第二行是n个整数ai(1<=i<=n)(1<=ai<=1000)。
对于100%的数据,1<=n<=10,1<=k<=10^9

Output

输出第k个Easy Number。

Sample Input

3 5
2 3 5

Sample Output

6

分析

  • 起初我是用了个这样的方法:每个给出的数弄个指针对着它到哪个数,然后每次选指针中最小的数,然后它向上加 a[i],知道选出 k 个数,类似这题(点击链接),可是复杂度是 O(k*n),好像还是超时了。
  • 于是才知道另一种方法,介于 n 很少,用容斥,二分一下答案,然后用容斥原理算出小于等于它的数中的“倍数”个数,然后与 k 比较即可。
  • 对于容斥的方法,开始我用了个 dfs(s,x,dep),意为 还要选 dep 个数乘,选了的数的乘积为s,剩下的数从 x 开始选,可是好像答案不对,后来换了个方法,具体看程序吧。

程序

#include <cstdio>
#define he(x,y) (x*y/gcd(x,y))
long long n,k,p,i,j,o,l,r,mid,S,ans,a[200];
long long gcd(long long b,long long c){return c?gcd(c,b%c):b;}

int main(){
    freopen("1.txt","r",stdin);
    scanf("%lld%lld",&n,&k);
    for (i=1; i<=n; i++) scanf("%lld",&a[i]);
    for (r=a[1]*k,mid=l+r>>1,S=0; l<=r; mid=l+r>>1,S=0){
        for (i=p=1,o=0; i<(1<<n); i++,p=1,o=0){
            for (j=1; j<=n; j++)
                if (i&(1<<(j-1))) p=p*a[j]/gcd(p,a[j]),o++;
            S+=((o&1)?1:-1)*(mid/p);
        }
        if (S>=k){ans=mid,r=mid-1; continue;}
        l=mid+1;
    }

    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值