zoukankan      html  css  js  c++  java
  • 【09NOIP提高组】Hankson 的趣味题(信息学奥赛一本通 1856)(洛谷 1072)

    题目描述

      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 的个数。请你帮助他编程求解这个问题。

    输入格式

      输入文件名为 son.in。第一行为一个正整数n,表示有n 组输入数据。接下来的n 行每行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证a0 能被a1 整除,b1 能被b0 整除。

    输出格式

      输出文件 son.out 共n 行。每组输入数据的输出结果占一行,为一个整数。对于每组数据:若不存在这样的 x,请输出0;若存在这样的 x,请输出满足条件的x 的个数;

    样例数据 1

    输入

    2
    41 1 96 288
    95 1 37 1776

    输出

    6
    2

    「说明」第一组输入数据,x 可以是9、18、36、72、144、288,共有6 个。第二组输入数据,x 可以是48、1776,共有2 个。

    备注

    「数据范围」
    对于 50%的数据,保证有1≤a0,a1,b0,b1≤10000 且n≤100。
    对于 100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000 且n≤2000。


     这道题呢,可以说是有很多种解法,我在这里简单讲三种。

    方法一:(可得五十分)

    由gcd(x,a0)=a1,lcm(x,b0)=b1,可知a1<=x<=b1,因此可以在这个区间内枚举x,求出此时的a1' 和b1',判断是否与原题给出的a1,b1相等。

    方法二:(可得七十分)

    令b0=t*m,x=t*n,gcd(m,n)=1,推出b1=t*m*n。而b1/b0=(t*m*n)/(t*m)=n为x的一个因子,这样就可以在已知一个因子的情况下,枚举进行判断。

    --->以上两种方法都并不是很难想,在考场上能得到这部分保底分已经足够了,就算没有把握AC,能骗到部分分也挺好的啦(*´・v・)

    方法三:(可得一百分)

    由题意得b0*x=b1*gcd(x,b0),x=b1/b0*gcd(x,b0),令i=gcd(x,b0)∈[1,根号b0],分别判断x=b1/b0*i和x=b1/b0*(b0/i)是否满足条件,然后还要注意处理特殊情况(即当根号b0恰好也满足条件时)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e6+5,inf=1<<29;
     4 long long n,ans,tot;
     5 int read()
     6 {
     7     int f=1;char ch;
     8     while((ch=getchar())<'0'||ch>'9')
     9         if(ch=='-')f=-1;
    10     int res=ch-'0';
    11     while((ch=getchar())>='0'&&ch<='9')
    12         res=res*10+ch-'0';
    13     return res*f;
    14 }
    15 void write(int x)
    16 {
    17     if(x<0)
    18     {
    19         putchar('-');
    20         x=-x;
    21     }
    22     if(x>9)write(x/10);
    23     putchar(x%10+'0');
    24 }
    25 int gcd(int x,int y)
    26 {
    27     if(y==0)return x;
    28     else return gcd(y,x%y);
    29 }
    30 int main()
    31 {
    32     n=read();
    33     while(n--)
    34     {
    35         int a0,a1,b0,b1;
    36         a0=read();a1=read();b0=read();b1=read();
    37         ans=0;
    38         for(int i=1;i*i<b0;i++)
    39             if(b0%i==0)
    40             {
    41                 int x=b1/b0*i;
    42                 if(gcd(x,b0)==i&&gcd(x,a0)==a1)ans++;
    43                 x=b1/b0*(b0/i);
    44                 if(gcd(x,b0)==b0/i&&gcd(x,a0)==a1)ans++;
    45             }    
    46         int k=int(sqrt(b0));
    47         if(k*k==b0)
    48         {
    49             int x=b1/b0*k;
    50             if(gcd(x,b0)==k&&gcd(x,a0)==a1)ans++;
    51         }
    52         write(ans);
    53         putchar('
    ');
    54     } 
    55     return 0;
    56 }
    View Code

    当然,这道优秀的题目还有其他的做法也很不错,我个人推荐一下以下两种做法

    点击查看优秀代码1  点击查看优秀代码2

  • 相关阅读:
    Get-CrmSetting返回Unable to connect to the remote server的解决办法
    Dynamics 365中的常用Associate和Disassociate消息汇总
    Dynamics 365 Customer Engagement V9 活动源功能报错的解决方法
    Dynamics Customer Engagement V9版本配置面向Internet的部署时候下一步按钮不可点击的解决办法
    Dynamics 365检查工作流、SDK插件步骤是否选中运行成功后自动删除系统作业记录
    注意,更改团队所属业务部门用Update消息无效!
    Dynamics 365的审核日志分区删除超时报错怎么办?
    Dynamics 365使用Execute Multiple Request删除系统作业实体记录
    Dynamics 365的系统作业实体记录增长太快怎么回事?
    Dynamics CRM日期字段查询使用时分秒的方法
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/11395702.html
Copyright © 2011-2022 走看看