200. Hankson的趣味题

// 200. Hankson的趣味题.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//


/*

https://www.acwing.com/problem/content/202/


Hanks 博士是 BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫 Hankson。

现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。

今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数。

现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:

已知正整数 a0,a1,b0,b1,设某未知正整数 x 满足:

x 和 a0 的最大公约数是 a1;
x 和 b0 的最小公倍数是 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。

但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。

因此他转而开始考虑如何求解满足条件的 x 的个数。

请你帮助他编程求解这个问题。

输入格式
输入第一行为一个正整数 n,表示有 n 组输入数据。

接下来的 n 行每行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开。

输入数据保证 a0 能被 a1 整除,b1 能被 b0 整除。

输出格式
输出共 n 行。

每组输入数据的输出结果占一行,为一个整数。

对于每组数据:若不存在这样的 x,请输出 0;

若存在这样的 x,请输出满足条件的 x 的个数;

数据范围
1≤n≤2000,
1≤a0,a1,b0,b1≤2∗109
输入样例:
2
41 1 96 288
95 1 37 1776
输出样例:
6
2
*/


#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

int T;
int a0, a1, b0, b1;
int curr;
vector<int> v;
int ans = 0;

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}


bool check(int x) {
	//cout << "x = " << x << endl;
	if (gcd(x, a0) != a1) 
		return false;
	if ( x / gcd(x, b0) *b0 != b1) 
		return false;
	return true;
}


void dfs(int idx) {
	if (idx*2 >= v.size()) {
		if (curr % a1 == 0 && check(curr)) {
			ans++;
		}
		return;
	}

	dfs(idx + 1);

	int back = curr;
	for (int i = 1; i <= v[idx * 2 + 1]; i++) {
		curr *= v[idx * 2];
		dfs(idx + 1);
	}
	curr = back;
}


void solve() {
	
	cin >> a0 >> a1 >> b0 >> b1;

	v.clear(); int bcp = b1;
	for (int i = 2; i <= bcp / i; i++) {
		int cnt = 0;
		while (bcp % i == 0) {
			cnt++;
			bcp /= i;
		}
		if (cnt != 0) {
			v.push_back(i); v.push_back(cnt);
		}
	}
	if (bcp != 1) {
		v.push_back(bcp); v.push_back(1);
	}
	curr = 1; ans = 0;
	dfs(0);

	cout << ans << endl;
}

int main()
{
	cin >> T;
	while (T--) {
		solve();
	}

	return 0;
}

posted on 2025-03-19 16:11  itdef  阅读(10)  评论(0)    收藏  举报

导航