HDU 4497 GCD and LCM(数学)

题目链接:Click here~~

题意:

问有多少个三元组 {x,y,z} ,使得 gcd(x,y,z) = G && lcm(x,y,z) = L。(顺序不同视为不同方案)

解题思路:

开始没注意括号里的条件,纠结了一天。

之前和队友 yzwsm 讨论过类似的二元组的问题,记得当时提到过将 G 和 L 分解质因子的方法,于是做这题时一下就联想到了。

首先一定有 G | L,在这个条件下,将两个数分解质因子,则一定能得到相同的质因子,且只是指数不同。(Note: 指数可以为 0 & 指数相同的项可以忽略)

即有 G = p1^a1 * p2^a2 * p3^a3 ……, L = p1^b1 * p2^b2 * p3^b3 ……(ai <= bi)。

由于方案的计数符合乘法原理,所以我们只需要考虑对于某个 pi 的方案数,最后相乘即可。

那么对于某个pi,第三个数的取值范围一定是 [a,b],我们分情况来考虑第三个数是否会等于a or b。

1、如果不等于,ans1 = A(3,2) * (b-a-1)。(Note:[a+1,b-1]  =>  cnt = b-a-1)

2、如果等于,ans2 = C(3,1) * 2。

相加可化简为 ans = 6 * (b-a)。


还可以用容斥来考虑,转下。


另一种思考:容斥原理,对于p1,一共有(t1+1)^3种,但是没有最高位t1的选法是不合法的,减去,一共有t1^3种选法不合法,没有最低位0的选法是不合法的,也是t1^3,发现多减了,所以加上多减的既没有最高位也没有最低位的(t1-1)^3,通过化简得6*t1`````


#include <vector>
#include <stdio.h>
#include <string.h>

using namespace std;

vector< pair<int,int> > v1,v2;

void get_pp(int g,int l)
{
    v1.clear();
    v2.clear();
	for(long long i=2;i*i<=l;i++)
	{
		int point_cnt1 = 0, point_cnt2 = 0;
		while(g % i == 0)
		{
			g /= i;
			point_cnt1 ++;
		}
		while(l % i == 0)
		{
			l /= i;
			point_cnt2 ++;
		}
		if(point_cnt1 != point_cnt2)
		{
			v1.push_back(make_pair(i,point_cnt1));
			v2.push_back(make_pair(i,point_cnt2));
		}
	}
    if(l != 1 && g != l)
	{
		v1.push_back(make_pair(l,0));
		v2.push_back(make_pair(l,1));
	}
}

long long solve(int g,int l)
{
    if(l % g != 0)
        return 0;
    get_pp(g,l);
	long long ans = 1;
	for(int i=0;i<(int)v1.size();i++)
		ans *= 6 * (v2[i].second - v1[i].second);
	return ans;
}

int main()
{
	int T,gcd,lcm;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&gcd,&lcm);
		printf("%I64d\n",solve(gcd,lcm));
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值