二解 Hankson的趣味题(AcWing 200)

题目传送门:https://www.acwing.com/problem/content/description/202/
题目描述:
Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。今天在课堂上,老师讲解了如何求两个正整数c1和c2的最大公约数和最小公倍数。现在Hankson认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:
已知正整数a0,a1,b0,b1,设某未知正整数x满足:
1、 x和a0的最大公约数是a1;
2、 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<bits/stdc++.h>
using namespace std;
typedef long long LL;

//TLE 16199 1 17707 312245238
//WA 21222 2 999993719 1999987438
//WA 90 2 9 18

int gcd(int a,int b){
	if (b == 0 )return a;
	return gcd(b,a%b);
}
int lcm(int a,int b){
	return 1ll * a * b / gcd(a,b);
}
int solve(int a0,int a1,int b0,int b1){
	int cnt = 0;
	for(int i = 1; i*i <= b1;i += 1){
		if(b1 % i!= 0 ) continue;   //此处剪枝,不能被b1整除的i肯定不是解,避免下面的函数调用耗费时间。
		if(gcd(a0,i) ==  a1 && lcm(b0,i) == b1){
			cnt ++;
		}
		if(b1/i != i && gcd(a0,b1/i) ==  a1 && lcm(b0,b1/i) == b1){
			cnt ++;
		}
	}
	return cnt;
}
int main(){
	int n,a0,a1,b0,b1,cnt=0;
	cin >> n;
	while(n--){
		scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
		printf("%d\n" ,solve(a0,a1,b0,b1));
	}
	return 0;
}

算法二:利用一个数可以分解为唯一分解定理的式子。
最大公约数和最小公倍数分别可以通过这些质因子上的指数来确定。分析每一个质因子的指数的可能性,根据乘法原理计算总的可能的数量。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
bool isprime[1000001];
int p[1000006],cnt,ans= 1;
void aishi(){
	memset(isprime,true,sizeof(isprime));
	isprime[0] = isprime[1] = false;
	for(int i = 2; i<= 1000000; i ++){
		
		if(isprime[i]){
			p[++cnt] = i;
			for( LL j = 1ll * i * i; j <= 1000000; j += i){
				isprime[j] = false;
			}
		}
	}
}
int get (int &x,int p){
	int s= 0;
	while(x % p == 0){
		s ++;
		x = x / p ;
	}
	return s;
}
int f(int &a0,int &a1,int &b0,int &b1,int t){
    int ma0 ,ma1,mb0,mb1,mx = 1;
    ma0 = get(a0,t),ma1 = get(a1,t) , mb0 = get(b0,t),mb1 = get(b1,t);
	if(ma0 > ma1 && mb0 < mb1 && ma1 == mb1) mx =  1;
	else if(ma0 > ma1 && mb0 == mb1 && ma1 <= mb1) mx = 1;
	else if(ma0 == ma1 && mb0 < mb1 && ma1 <=  mb1 ) mx =1;
	else if(ma0 == ma1 && mb0 == mb1 && ma1 <= mb1) mx = mb1 - ma1 + 1;
	else {
		return 0;
	}
	return mx;
}
int solve(int a0,int a1,int b0,int b1){
	int t;
	for(int i = 1; i<= cnt; i++){
		t = p[i];
		if( t > b1) break;   //µ±µ±Ç°µÄÖÊÊý´óÓÚʣϵÄb1ʱ£¬ºóÃæËùÓеÄÖÊÊý¶¼¿ÉÒÔ²»×öÁË£¬Ò»¶¨Ã»ÓÐÕâÑùµÄÖÊÒò×Ó¡£
		if(b1 % t != 0 ) continue;//Èç¹ûµ±Ç°ÖÊÊý²»Äܱ»b1Õû³ý£¬ÔòxÖп϶¨Ò²Ã»ÓиÃÖÊÒò×Ó¡£
		ans = ans * f(a0,a1,b0,b1,t);  //¸ù¾Ý³Ë·¨Ô­Àí
	}
	if(b1 != 1){  //µ±b1ºÜ´óʱ£¬¿ÉÄÜ´æÔÚ±Èɸ³öÀ´µÄÖÊÊý»¹´óµÄÖÊÒò×Ó£¬ÐèÒªµ¥¶À´¦Àí¡£
		t = b1;
		ans = ans * f(a0,a1,b0,b1,t);
	}
	return ans;
}

//TLE 16199 1 17707 312245238
//WA 21222 2 999993719 1999987438
//WA 90 2 9 18

int main(){
	int n,a0,a1,b0,b1,cnt=0;
	aishi();
	cin >> n;
	while(n--){
		ans = 1;
		cnt = 0;
		scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
		printf("%d\n" ,solve(a0,a1,b0,b1));
	}
	return 0;
}

发布了88 篇原创文章 · 获赞 22 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/xuechen_gemgirl/article/details/89025834