GCD and LCM HDU - 4497(质因数分解)

Problem Description

Given two positive integers G and L, could you tell me how many solutions of (x, y, z) there are, satisfying that gcd(x, y, z) = G and lcm(x, y, z) = L? 
Note, gcd(x, y, z) means the greatest common divisor of x, y and z, while lcm(x, y, z) means the least common multiple of x, y and z. 
Note 2, (1, 2, 3) and (1, 3, 2) are two different solutions.

Input

First line comes an integer T (T <= 12), telling the number of test cases. The next T lines, each contains two positive 32-bit signed integers, G and L. It’s guaranteed that each answer will fit in a 32-bit signed integer.

Output

For each test case, print one line with the number of solutions satisfying the conditions above.

Sample Input

2 
6 72 
7 33 

Sample Output

72 
0


大概题意

给出T组数据每组数据有两个数分别为x,y,z的最大公约数和
最小公倍数,让我们求出x,y,z总共有多少组不同组合方式;

具体思路
        考虑先分解最小公倍数。合数分解后,再分解最大公约数,可知,如果最大公约数中有最小公倍数中没有的质因数因子的话,那么答案肯定为0
        然后考虑每一个因子pi有设合数分解最小公倍数的个数为bi合数分解最大公约数的个数为bi
       
  下面有两种考虑方法
 
    1.排列组合
 
         易得三个数中的对于pi的情况必须有一个个数是bi,另一个是ai,然后就可以先选出两个位置一个bi一个ai然后最后一个位置上的个数一定介于ai和bi之间即(bi-ai-1)种情况。
         所以最后的公式为ans *=  A(3,2)*(bi-ai-1) = 6*(bi-ai-1) ;
 
       注意
 
         如果先筛素数的时候筛到1^6 然后如果L除以最后一个素数的时候不等于1,那么说明它(L的最后一个因子)一定是大于10^6的一个素数,因为10^12 = 10^6^2 > x^2>y;如果y存在
       一个非素数的因子k的话,有k*t = y 且k>x,则t<x则t已经被筛掉了。    所以剩下的因子一定是素因子。一开始没有考虑这种特殊情况wa掉了。还要注意只有当(bi-ai-1) 有意义的时候才可以计算,因为如果bi==ai的时候可以发现正确结果是对于这一位应该是只用一种情况,就是三个数都相等,所以要特判一下。
 
 
    2. 容斥定理
 
        同样是考虑每个因子,有所有的情况是每个位置都可以取(bi-ai+1)种情况即(bi-ai+1)^3,要减去没有bi个因子的情况和没有ai个因子的情况即2*(bi-ai)^3
       然后发现减多了,要加上同时没有因子ai和bi的情况即(bi-ai-1)^3 这里同样要注意上面的注意。
 
操作代码如下
 
#include<iostream>
using namespace std;
#define N 100100
#define ll long long
ll d[N][2],e[N][2],cntn,cntm;
void devide(int n,int m)
{
    cntn=cntm=0;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            int num=0;
            while(n%i==0)
            {
                num++;
                n/=i;
            }
            d[++cntn][0]=i,d[cntn][1]=num;
        }
    }
    for(int i=2;i*i<=m;i++)
    {
        if(m%i==0)
        {
            int num=0;
            while(m%i==0)
            {
                num++;
                m/=i;
            }
            e[++cntm][0]=i,e[cntm][1]=num;
        }
    }
    if(n>1)d[++cntn][0]=n,d[cntn][1]=1;
    if(m>1)e[++cntm][0]=m,e[cntm][1]=1;
}
ll solve(int n,int m)
{
    if(m%n!=0)
        return 0;
    devide(n,m);
    ll ans=1,v;
    for(int i=1;i<=cntm;i++)
    {
        int flag=0;
        for(int j=1;j<=cntn;j++)
          if(e[i][0]==d[j][0])
         {
             flag=1;
             v=j;
             break;
         }
         if(!flag)
            ans=ans*6*e[i][1];
         else
         {
             ll t=e[i][1]-d[v][1];
             if(t==0)continue;
             ans=ans*6*t;
         }
    }
    return ans;
}
int main()
{
    int t;
    int n,m;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        ll ans=solve(n,m);
        cout<<ans<<endl;
    }
    return 0;
}

 实践是检验真理的唯一标准;

猜你喜欢

转载自www.cnblogs.com/dwj-2019/p/11348920.html