题目链接:http://codeforces.com/problemset/problem/340/A
这道题目理解不难,就是在[a, b]区间内,找出同时能够被x和y整除的个数。第一次想当然的开了两个2·109的数组,分别标记能被x和y的数字,内存受不了,返回CE。仔细想了下,开这么大的一个数组没有必要,直接在[a, b]枚举每一个数,能够同时整除x和y的数就统计下来,过了PT,然而很快就被hacked(还是第一次遇到的= =,不过也好,能帮助养成严谨的思维); 第三次,稍稍改良了算法,求x和y的最小公倍数,在[a, b]的范围内累加最小公倍数的个数,直到大于b为止,然而没考虑到最小公倍数有可能小于a,于是wa。第四次,改正这个错误后,再次PT,然后又被hacked。一题被hacked两次,前无古人,后无来者啊~~~彻底绝望,不知道哪里有错......第二天再做,重交被hacked的代码(比赛中貌似被hacked的数据没有给出的)TLE,算法太差啦!!!估计被hacked的原因就是如此吧。
说了那么多废话,步入正题。
2·109,数据量太大!不优化肯定过不了!由于是要统计同时被x和y整除的个数,那么符合条件的数肯定满足: 1 * M,2 * M,3 * M,......N * M(M表示x和y的最小公倍数)。问题就转化为在[a, b]中找到有多少个M。我的做法是,从a往后开始枚举,直到遇上第一个能同时被x和y整除的数(假设为 i );接着从b往前开始枚举,也是直到遇上第一个能同时被x和y整除的数(假设为 j )。最后的结果就是 ( j - i ) / 最小公倍数 + 1 。 这个算式的意思为:j / 最小公倍数:[1, b]之前有多少个能同时整除x和y的数,i / 最小公倍数:[1, a]之前有多少个能同时整除x和y的数,+1是因为相减之后大于等于a的第一个能同时整除x和y的数实质是没有统计的。
1 #include <iostream>
2 #include <stdio.h>
3 #include <stdlib.h>
4 using namespace std;
5
6 int gcd(int x, int y) // 求最小公倍数
7 {
8 while (x != y)
9 {
10 if (x > y)
11 x = x - y;
12 else
13 y = y - x;
14 }
15 return x;
16 }
17
18 int main()
19 {
20 int x, y, a, b, i;
21 while (scanf("%d%d%d%d", &x, &y, &a, &b) != EOF)
22 {
23 int temp = x / gcd(x, y) * y;
24 // printf("temp = %d\n", temp);
25 i = (a > temp ? a : temp); // i 保证要在[a, b]区间内,以便后面的枚举操作
26 while (i % x || i % y) // 找出第一个在[a, b]区间中能同时整除x和y的数
27 i++;
28 // printf("i = %d\n", i);
29 while (b % x || b % y) // 找出最后一个在[a, b]区间中能同时整除x和y的数
30 b--;
31 // printf("b = %d\n", b);
32 printf("%d\n", (b - i) / temp + 1);
33 }
34 return 0;
35 }