题目链接http://acm.hdu.edu.cn/showproblem.php?pid=6286
题目大意是,给出两个区间,A,B。从两个区间中各自任意取出一个数,使得
是2018的倍数。
既然要组合出2018的倍数,就先要知道2018有些什么因子,很容易得出,2018只有1、2、1009、2018四个因数。
那么组合2018的方式也是有一个直接思路的,若x是2018的倍数,那么x的因子里面必须有2和1009。
在组合出2018的倍数时,常常有多算少算的情况。
最为根本的原因就是,组合时可以用2*1009或者2018*任何数来组合。在计算的过程中,总是考虑不清楚,,不过从集合的方向去思考就会变的明了。
令题目给出的 a~b 间的数集合为 A ,c~d 间的数为集合B 。
另外,A的子集 表示 集合A中 2 的倍数。
表示集合A 中2018的倍数
代表 A 中1009的倍数。
同样,对B 也有
。
既然2018的倍数本身很容易混淆,那么我们就分两种情况。A集合中选出 ai B 集合中选出 bj ,两种情况如下:
一、ai bj 是2018的倍数。
二、ai bj 都不是2018的倍数 。
首先看ai bj 是2018倍数的情况。如果 ai 是2018的倍数,那么 bj 可以取任何数,这里就有 种,这里的
代表集合 B 的总数。
同样,如果 bj 是2018的倍数,ai 就可以是任何数那么这里就有 中。这就是两个数 ai bj 分别为2018的倍数的种类数,结果
。
这里我们已经把 ai bj 都为2018的倍数的可能性包含在了这两种情况中。而且重复算了两次,所以最终结果要减去一次。ai bj同时为2018的倍数种类数为 。所以最后的结果应该为
。
再来看第二种情况
ai 和 bj 都不是2018的倍数,当然我们说的是为1009或者2的倍数,但不是2018的倍数的数。
这里面又可以分为两种子情况
1、ai 为1009但不为2018的倍数,bj 为2但不为1009的倍数。
2、反过来ai 为2但不为1009的倍数,bj为1009但不为2018的倍数.
其实分别可以用两个式子来表示,
1、 这个式子是很好理解的,第一项代表ai 为1009但不为2018的倍数,第二项代表bj 为2但不为1009的倍数。
2、 同理。
这两种肯定是互斥独立的,同样,这里所有的情况和为种,这里所有的情况肯定和第一种2018的情况没有任何重复。因为这里的每一项都去除了2018的倍数。
那么最后的解应该为,
看上去这个公式又臭又长,但是其实每一项都非常好算的。
下面是代码:
#include<iostream>
using namespace std;
typedef long long ll;
int main(){
ll sum,a,b,c,d;
sum=0;
while(cin>>a>>b>>c>>d){
ll a2=b/2-(a-1)/2;
ll a8=b/2018-(a-1)/2018;
ll a9=b/1009-(a-1)/1009;
ll b2=d/2-(c-1)/2;
ll b8=d/2018-(c-1)/2018;
ll b9=d/1009-(c-1)/1009;
ll al=b-a+1,bl=d-c+1;
sum=al*b8+bl*a8-a8*b8+(a9-a8)*(b2-b8)+(b9-b8)*(a2-a8);
cout<<sum<<endl;
}
return 0;
}