Hankson的趣味题

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-11 21:47:29

【问题描述】
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\n");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\n");
            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\n");
            return;
        }
    }
    printf("%lld\n",ans);
}

int main()
{
    cl();
    scanf("%d",&n);
    while (n--)
    {
        scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
        doit();
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!