题目链接: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 里面取的数都符合分给两个人的条件。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef __int64 LL; 9 LL cnt1, cnt2, x, y; 10 11 bool check(LL v) 12 { 13 LL f1 = v / x; 14 LL f2 = v / y; 15 LL both = v / (x*y); 16 LL others = v - f1 - f2 + both; 17 LL ff1 = f1 - both; // second 18 LL ff2 = f2 - both; // first 19 20 LL gf1 = (cnt1 - ff2 >= 0 ? cnt1 - ff2 : 0); // 注意这个相减有可能为负数,所以要判断下 21 LL gf2 = (cnt2 - ff1 >= 0 ? cnt2 - ff1 : 0); 22 23 return (gf1 + gf2 <= others); 24 } 25 26 int main() 27 { 28 while (scanf("%I64d%I64d%I64d%I64d", &cnt1, &cnt2, &x, &y) != EOF) 29 { 30 LL l = 1, r = 1e18; 31 while (l < r) 32 { 33 LL m = (l+r) >> 1; 34 if (check(m)) 35 r = m; 36 else 37 l = m + 1; 38 } 39 printf("%I64d\n", r); 40 } 41 return 0; 42 }