hdu 4497 GCD and LCM(数学知识很重要)

GCD and LCM

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 214    Accepted Submission(s): 105


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
 

Source
 

Recommend
liuyiding
  题意:
给你三个数的最大公约数g和最小公倍数问你满足条件的这三个数有多少种。
思路:
来源于大神博客见此
将满足条件的一组x,z,y都除以G,得到x‘,y',z',满足条件gcd(x',y',x') = 1,同时lcm(x',y',x') = G/L.(转化很经典)
特判,当G%L != 0 时,无解。
然后素数分解G/L,假设G/L = p1^t1 * p2^t2 *````* pn^tn。
满足上面条件的x,y,z一定为这样的形式。

x' = p1^i1 * p2^i2 *```* pn^in.
y' = p1^j1 * p2^j2 * ```*pn^jn.
z' = p1^k1 * p2^k2 * ```*pn^kn.

为了满足上面的条件,对于p1,一定有max(i1,j1,k1) = t1.min(i1,j1,k1) =0;则当选定第一个数为0,第二个数为t1时,第三个数可以为0-t1,又由于有顺序的,只有

(0,t1,t1) 和(0,t1,0)这两种情形根据顺序只能产生6种结果,其他的由于三个数都不一样,一定能产生6种,所以最后产生了6*(t1-1)+3*2 = 6*t1种(t1-1是因为t1从0开始所以一共有t1+1个数除去0.和t1还剩t1-1个数),根据乘法原理以及关于素数分解的唯一性,反过来,素数组合必然也是唯一的数,一共有6*t1 * 6*t2 *`````*6*tn种选法。
详细见代码:
#include <iostream>
#include<stdio.h>
#include<map>
using namespace std;
const int maxn=10000100;
int cnt;
int fac[100][2];
void getprime(int x)
{
    int i;
    cnt=0;
    for(i=2; i<maxn; i++)
    {
        if(x%i==0)
        {
            fac[cnt][0]=i;
            fac[cnt][1]=1;
            x/=i;
            while(x%i==0)
            {
                fac[cnt][1]++;
                x/=i;
            }
            cnt++;
        }
        if(x==1)
            break;
    }
}
int main()
{
    int t,g,l,i,ans;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&g,&l);
        if(l%g!=0)
        {
            printf("0\n");
            continue;
        }
        getprime(l/g);
        ans=1;
        for(i=0;i<cnt;i++)
            ans*=6*fac[i][1];
        printf("%d\n",ans);
    }
    return 0;
}

另一种思考:容斥原理,对于p1,一共有(t1+1)^3种,但是没有最高位t1的选法是不合法的,减去,一共有t1^3种选法不合法,没有最低位0的选法是不合法的,也是t1^3,发现多减了,所以加上多减的既没有最高位也没有最低位的(t1-1)^3,通过化简得6*t1`````
详细见代码:
#include <iostream>
#include<stdio.h>
#include<map>
using namespace std;
const int maxn=1000010;
int cnt;
int fac[100][2],a[100],ptr;
map<int,int> mp1,mp2;
void getprime(int x)
{
    int i;
    cnt=0;
    for(i=2; i<maxn*10; i++)
    {
        if(x%i==0)
        {
            fac[cnt][0]=i;
            fac[cnt][1]=1;
            x/=i;
            while(x%i==0)
            {
                fac[cnt][1]++;
                x/=i;
            }
            cnt++;
        }
        if(x==1)
            break;
    }
}
int main()
{
    int t,g,l,i,m1,m2,ans;
    long long sum,tmp;
    bool flag;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&g,&l);
        mp1.clear();
        mp2.clear();
        flag=false;
        getprime(l);
        ptr=cnt;
        for(i=0;i<cnt;i++)
        {
            mp1[fac[i][0]]=fac[i][1];
            a[i]=fac[i][0];
        }
        getprime(g);
        for(i=0;i<cnt;i++)
        {
            if(fac[i][1]>mp1[fac[i][0]])
            {
                flag=true;
                break;
            }
            mp2[fac[i][0]]=fac[i][1];
        }
        if(flag)
        {
            printf("0\n");
            continue;
        }
        ans=1;
        for(i=0;i<ptr;i++)
        {
            sum=0;
            m1=mp1[a[i]];
            m2=mp2[a[i]];
            if(m1==m2)
                continue;
            //printf("%d %d %d\n",a[i],m1,m2);
            tmp=m1-m2+1;
            sum+=tmp*tmp*tmp;
            tmp=m1-m2;
            sum-=2*tmp*tmp*tmp;
            tmp=m1-m2-1;
            sum+=tmp*tmp*tmp;
            ans*=sum;
        }
        printf("%d\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值