链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1785
Description:
静竹的好友欧几里德暗中对其使坏,用毒蛇咬伤了静竹。还有人性的是,欧几里德把解药放到了一个密码箱里,静竹成功将其打开后,发现里面竟然还有一个箱子,欧几里德告诉她这个是老板放的,同样,老板对这个箱子也加了类似的密码,静竹要打开这个不知道是不是最后一个的箱子必须通过箱子上面的两个数来计算出密码,数学能够再次把静竹成功解救吗?
Input:
多组测试数据,对于每组数据:
输入数据包含两个整数x, y 。(1≤x,y≤10^9)
处理到文件结束。
Output:
对于每组输入的x,y 输出一个整数表示密码并换行。
密码是由p-q的绝对值组成,其中p,q满足
① p, q 都是正整数
② GCD(p,q) = x;
③ LCM(p,q) = y.
由于存在多组解,输出p-q绝对值最小的那种情况即可。
如果p,q不存在,输出Vagaa;
分析:
数论题。
本题的数据量较大,需要用较之前类似题目更优化的解法来解决。
考虑一下最大公约数和最小公倍数的特性即可。假设最大公约数为g,最小公倍数为l,则存在两个数c、d,有
a = c*g, b = d*g, l = c*d*g, 且c、d互素。现在问题变成要使c和d的差值最小。
可以先对乘积c*d进行分解质因数,那样问题就等价于如何把这些质因数分成两个集合。因为题目数据的规模都比较小,所以质因数的个数不是很多。考虑到c和d互质,所以同一个质因子只可能属于其中一个集合。所以可以采用枚举法来决定哪些质因数是属于a的,哪些是属于b的,枚举量最大也只有2^9=512而已。
解题代码如下:
#include <stdio.h>
#include <string.h>
#include <time.h>
int mark[333333];
int pn, pr[5000];
int p[10], n;
int best, best1, bestr;
void makeprime(){
int i, j;
pn = 0;
memset(mark, 0, sizeof(mark));
for (i=2; i<33333; i++){
if (!mark[i]){
pr[++pn] = i;
for (j = i*i; j < 33333; j += i)
mark[j] = 1;
}
}
}
void dfs(int x, int l, int r){
if (x > n){
if (l > r) return;
if (r - l < best){
best = r - l;
}
return;
}
dfs(x + 1, l * p[x], r);
dfs(x + 1, l, r * p[x]);
}
int main(){
int a, b, i;
makeprime();
while (scanf("%d %d", &a, &b)!=EOF){
if (b%a != 0){
printf("Vagaa\n");
continue;
}
b /= a;
best = b + 1;
n = 0;
for (i=1; i<=pn && pr[i]*pr[i]<=b; i++){
if (b % pr[i] == 0){
n++, p[n] = 1;
}
while (b % pr[i] == 0){
p[n] *= pr[i], b /= pr[i];
}
}
if (b > 1) p[++n] = b;
dfs(1, 1, 1);
printf("%d\n", best*a);
}
}
后续解法待续。。。