您的位置:首页 > 其它

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

2017-08-23 17:07 525 查看
题单第六题: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: