题目链接:http://codeforces.com/problemset/problem/483/B
题目意思:有两个 friends,需要将 cnt1 个不能整除 x 的数分给第一个friend,cnt2 个不能整除 y 的数分给第二个friend。x 和 y 都是素数来的。要求求出最小的 v,v 表示可以从1,2,...,v 中取数。
开始我做这条题的时候是用很常规的方法做的,结果可想而知,WA,MLE,TLE。只能看题解啦,不会嘛~~~题解真是非常清晰、明白、易懂。
等我用中文来解释下吧。要用到二分搜索!因为它符合一个条件,如果 v 这个数符合分配给两个人的所有条件,那么 v+1 就更加可以啦~~~所以二分是一个好选择,还有数据量太大啦,1e18 ! 正常做肯定超时!
首先给出一幅本人呕心沥血画的一幅东西:
设几个变量 f1,f2,both,others,f1',f2',v。
v:二分枚举的数,取值是 1 ~ 1e18,图中的全集也~~~
f1:能被 x 除尽的个数,v/f1
f2: 能被 y 除尽的个数,v/f2
both:同时被 x 和 y 除尽的个数。由于 x 和 y 都是素数,所以就相当于能被 x*y 整除。v/(x*y)
others: 既不能被 x 也不能被 y 整除的个数。v - f1 - f2 + both (容斥原理的精髓,both 被减了两次,所以最终要加回一次)
f1':能分配给 第二个人(除不尽 y)但又不是从others里面选择的数。f1' = f1 - both
f2': 能分配给 第一个人(除不尽 x)但又不是从others里面选择的数。f2' = f2 - both
然后给出的 cnt1 和 cnt2
cnt1 = f2' + others
cnt2 = f1' + others
那么最终要判断的是 cnt1 - f2' + cnt2 - f1' 是否 <= others 了。因为从 others 里面取的数都符合分给两个人的条件。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std; typedef __int64 LL;
LL cnt1, cnt2, x, y; bool check(LL v)
{
LL f1 = v / x;
LL f2 = v / y;
LL both = v / (x*y);
LL others = v - f1 - f2 + both;
LL ff1 = f1 - both; // second
LL ff2 = f2 - both; // first LL gf1 = (cnt1 - ff2 >= ? cnt1 - ff2 : ); // 注意这个相减有可能为负数,所以要判断下
LL gf2 = (cnt2 - ff1 >= ? cnt2 - ff1 : ); return (gf1 + gf2 <= others);
} int main()
{
while (scanf("%I64d%I64d%I64d%I64d", &cnt1, &cnt2, &x, &y) != EOF)
{
LL l = , r = 1e18;
while (l < r)
{
LL m = (l+r) >> ;
if (check(m))
r = m;
else
l = m + ;
}
printf("%I64d\n", r);
}
return ;
}