题目链接: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 }