题目
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^9Output
输出第k个Easy Number。
Sample Input
3 5
2 3 5Sample 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);
}