UVALive 4683 Find The Number(容斥+二分)

来源:互联网 发布:手机编程游戏 编辑:程序博客网 时间:2024/06/05 08:04

题单第六题:http://blog.csdn.net/shengtao96/article/details/52490020
题意:给你k个数(保证这k个数不能互相整除),找出第n个只能被这k个数里面的某一个数整除的数(不能被2个或者2个以上的数整除)。
看完题想想,应该就能二分来做,问题是怎么找第n个只能被这k个数字里面某个数字整除的数字。容斥的时候我们把相交的部分全部减去,只剩下各个集合不相交的部分就好了。
这里写图片描述
只算空白部分,容斥的时候减掉红色部分。
不过我算错了,看上边那图就能看出我做法错了这里写图片描述
我看的题单中的解法,虽然不明白为啥那样,但是画个图自己算算,发现还真是那样。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL One = 1;const LL INF = One<<61;LL dnum[13];LL cnt[5000];LL lcms[5000];LL lcm(LL a, LL b){    return a/__gcd(a,b)*b;}void init(LL k){    for(LL i = 1; i < (1<<k); ++i)    {        LL mult = 1;        LL c = 0;        for(LL j = 0; j < k; ++j)        {            if(i&(1<<j))            {                ++c;                mult = lcm(mult,dnum[j]);            }        }        lcms[i] = mult;        cnt[i] = c;    }}LL C(LL num, LL k){    LL limit = One << k;    LL res = 0;    for(LL i = 1; i < limit; ++i)    {        if(cnt[i]&1) res += num/lcms[i]*cnt[i];        else res -= num/lcms[i]*cnt[i];    }    return res;}int main(){    LL T,k;    LL n;    scanf("%lld",&T);    while(T--)    {        scanf("%lld %lld",&k,&n);        for(LL i = 0; i < k; ++i)            scanf("%lld",&dnum[i]);        init(k);        LL L = 1;        LL R = INF;        LL mid;        while(L <= R)        {            mid = (L+R) >> 1;            if(C(mid,k) < n)                L = mid + 1;            else                R = mid - 1;        }        printf("%lld\n",L);    }    return 0;}
阅读全文
0 0