• 【转】【数论】【codevs】1012 最大公约数和最小公倍数问题


    [问题描述]
    输入二个正整数x0,y0(2≤x0≤100000,2≤y0≤1000000),求出满足下列条件的P、Q的个数。
    条件:1、P、Q是正整数
    2、要求P、Q以xO为最大公约数,以yO为最小公倍数。
    试求,满足条件的所有可能的两个正整数的个数。
    [样例]
    输入:x0=3 y0=60
    输出:4
    说明:(不用输出)此时的 P Q 分别为,
    3 60
    15 12
    12 15
    60 3
    所以,满足条件的所有可能的两个正整数的个数共4种。

    知识准备:

     p,q的最大公约数为x0,则:

     p%x0=0,q%x0=0

    假设 p1=p/x0   q1=q/x0

    进行如下推导:

    1。如果p1=q1,则根据最大公约数的定义,p1=q1=1,p=q=x0,根据最小公倍数的定义,p=q=y0,  x0=y0=p=q

    2.如果p1!=q1,根据最大公约数的定义,p1q1除了1以外没有其他相同的因子,即p1,q1互质。

    3.根据最小公倍数的定义,y0=pq/x0, p1=p/x0,q1=q/x0,则可推出如下的等式:p1q1=y0/x0.

      根据以上分析,可以推出以下算法:

     

       1。如果y0%x0!=0,p,q不存在。

       2。如果y0=x0,则存在一组p,q,p=q=x0=y0

       3. 1y0/x0之间查找满足p1q1=y0/x0p1,q1互质的数据对。

     

    参考程序如下:

    #include<iostream>

    #include<cstdio>

    using namespace std;

    long x,y,p,q,i,s;

    int hz(long p,long q)//判断p,q互质

    {

        long j;

        for(j=2;j<=p;j++)

        if(p%j==0&&q%j==0)

           return 0;

        return 1;  

       

    }    

    int main()

     {  

         freopen("in.txt","r",stdin);

         freopen("out.txt","w",stdout);

         while(cin>>x>>y)

         {

             if(y%x!=0)

               cout<<0<<endl;

             else if(y==x)cout<<1<<endl;

             else

                {

                    s=0;

                    i=y/x;

                    for(p=1;p<=i;p++)

                     for(q=1;q<=i;q++)

                      if((p*q==y/x)&&hz(p,q))

                        s++;

                 cout<<s<<endl;  

                }     

         }   

         return 0;

     }   

     

    二。对算法的改进

    1.猜想

       根据前面的分析:如果p,q的最大公约数为x,最小公倍数为y,则只要查找满足乘积为y/x且互质的p1,q1数据对就可以了。这样的数据对个数有没有规律呢?

    猜想:设y0/x0的质因子个数为k,则满足条件的p,q对个数为2^k,即集合中子集合的数目。

    证明:

    假设y0/x0k个质因子,y0/x0=a1*a1*…ak (ai是质数,算术基本定理)

    要使得p1*q1=y0/x0,p1,q1互质,则p1,q1不能含有相同的的质因子,因此p1,q1的选择总数为

    如何统计整数s的质因子个数k?最简单的方法是线性查找。2开始依次累加,第一个能整除s的数据必然为质因子,通过循环整除操作排除该质因子后,下一个能整除s的数据还是质因子。

    算法如下:

    1. i=2;

    2. While (s%i!=0) s++;

    3. K++;

    4. While (s%i==0)  s=s/i;

    5. 继续执行语句2

    参考程序如下:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    long x,y,p,q,i,s,j,k;
    long total;//保存2^k   
    int main()
     {   
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
         while(cin>>x>>y)
         {
             if(y%x!=0)
               cout<<0<<endl;
             else if(y==x)cout<<1<<endl;
             else
                {
                    s=0;
                    i=y/x;
                    j=2;
                    while(i>1)
                  {  
                    while(i%j!=0)  j++;
                    s++;
                    while(i%j==0) i=i/j;
                  }    
                    total=1;
                    for(j=1;j<=s;j++)
                     total*=2;  //计算2^k  
                 cout<<total<<endl;   
                }      
         }    
         return 0;
     } 

  • 相关阅读:
    java内联函数
    jvm垃圾回收
    jvm内存管理
    java进程和线程的区别
    jvm
    简单易学的SSM(Spring+SpringMVC+MyBatis)整合
    Spring之声明式事务
    SpringMVC知识点小结
    Servlet之文件的上传与下载
    java使用字节流和字符流实现文件复制
  • 原文地址:https://www.cnblogs.com/miaowTracy/p/5287826.html
Copyright © 2020-2023  润新知