zoukankan      html  css  js  c++  java
  • Hankson的趣味题

    【问题描述】
    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的个数;

    【输出输出样例】
    son.in
    2
    41 1 96 288
    95 1 37 1776

    son.out
    6
    2

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

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

    分析:
    根据最小公倍数和最大公约数分解质因数指数的特殊关系进行优化
    比如两个数,分解质因数可以得到以下的式子
    A=p1^a1+p2^a2+p3^a3……
    B=p1^b1+p2^b2+p3^a3……
    例如6和21就可以分解成
    6=2^1+3^1+5^0+7^0……
    21=2^0+3^1+5^0+7^1……
    最大公约数=2^(min(a1,b1))+3^(min(a2,b2))+5^(min(a3,b3))+7^(min(a4,b4))…
    最小公倍数=2^(max(a1,b1))+3^(max(a2,b2))+5^(max(a3,b3))+7^(max(a4,b4))…
    我们可以先预处理50000以内的质数,
    然后每读入一组数据,初始答案ans=1,
    然后我们循环质数,看a0、a1、b0、b1里面有多少个该质数因子,

    我们设求出来的该因子个数分别是t1、t2、t3、t4
    如果数据合法,那么t1>=t2,t3<=t4
    这里写图片描述
    根据最大公约数和最小公倍数的定义,
    我们要求的数所拥有的该质因子个数s必须要同时满足以下限制条件:
    若t1>t2,则s=t2
    若t1=t2,则s>=t2 //t2是t1和s取min的结果

    若t3 < t4,则s=t4
    若t3=t4,则s<=t4 //t4是t3和s取max的结果

    若t1 < t2||t3>t4—->无解

    让我们来看一下判断:

    if (t1>t2) f1=1;
    mn=t2;
    if (t3<t4) f2=1;
    mx=t4;
    if (!(f1||f2)) ans=ans*(mx-mn+1);
    else if (f1==0&&f2==0&&mx!=mn) 
    {
         printf("0
    ");return;
    }

    如果t1>t2 说明s只能等于t2,f1=1
    如果t3 < t4 说明s只能等于t3,f2=1
    如果规定只能等于一个值,而(f1=1,f2=1),且mn!=mx,ans=0
    只要有一个规定值了,ans*=1

    然而

    luogu上第二个点过不去。。。

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #define ll long long
    
    using namespace std;
    
    const int N=500000;
    const int INF=0x33333333;
    ll sshu[50010],tot=0;
    bool no[500010];
    ll a0,a1,b0,b1;
    int t1,t2,t3,t4,n;
    
    void cl()
    {
        memset(no,0,sizeof(no));
        for (ll i=2;i<=N;i++)
        {
            if (!no[i]) sshu[++tot]=i;
            for (int j=1;sshu[j]*i<=N&&j<=tot;j++)
            {
                no[i*sshu[j]]=1;
                if (i%sshu[j]==0) break;
            }
        }
    }
    
    void doit()
    {
        ll ans=1;
        int i,j,mx=0,mn=INF;
        bool f1,f2;
        for (i=1;i<=tot;i++)  //对于每个因子都要这样处理 
        {
            t1=t2=t3=t4=0;
            f1=0,f2=0;
            mn=mx=-1;
            while(a0>1&&a0%sshu[i]==0) t1++,a0=a0/sshu[i];
            while(a1>1&&a1%sshu[i]==0) t2++,a1=a1/sshu[i];
            while(b0>1&&b0%sshu[i]==0) t3++,b0=b0/sshu[i];
            while(b1>0&&b1%sshu[i]==0) t4++,b1=b1/sshu[i];
            if (t1<t2||t3>t4) {
                printf("0
    ");
                return;
            }
            if (t1>t2) f1=1;
            mn=t2;
            if (t3<t4) f2=1;
            mx=t4;
            if (!(f1||f2)) ans=ans*(mx-mn+1);
            else if (f1&&f2&&mx!=mn) 
            {
                printf("0
    ");
                return;
            }
        }
        printf("%lld
    ",ans);
    }
    
    int main()
    {
        cl();
        scanf("%d",&n);
        while (n--)
        {
            scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
            doit();
        }
        return 0;
    }
  • 相关阅读:
    算法基础<七> 加权有向图
    union 分页/group/join 复杂查询(.net core/framework)
    扩展Elasticsearch客户端简化ES查询(.net core/framework)
    对EF Core进行扩展使支持批量操作/复杂查询
    Grpc对象转proto代码工具
    扩展ADO.net实现对象化CRUD(.net core/framework)
    Sublime Text 4 破解笔记
    python三元表达式(三目运算符)的坑
    xaf-常见问题解答
    xaf.blazor中如何开启诊断按钮
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673446.html
Copyright © 2011-2022 走看看