P1072 Hankson 的趣味题

本文探讨了一种逆向思维的数学问题,即已知两个正整数的最大公约数和最小公倍数,反求满足特定条件的未知数的个数。通过分解质因数并分析条件限制,给出了编程解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在课堂上,老师讲解了如何求两个正整数c_1c1​ 和 c_2c2​ 的最大公约数和最小公倍数。现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a_0,a_1,b_0,b_1a0​,a1​,b0​,b1​,设某未知正整数xx 满足:

1. xx 和 a_0a0​ 的最大公约数是 a_1a1​; 

2. xx 和 b_0b0​ 的最小公倍数是b_1b1​。

Hankson 的“逆问题”就是求出满足条件的正整数xx。但稍加思索之后,他发现这样的xx 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 xx 的个数。请你帮助他编程求解这个问题。

【数据范围】

对于 50%的数据,保证有 1≤a_0,a_1,b_0,b_1≤100001≤a0​,a1​,b0​,b1​≤10000 且n≤100n≤100。

对于 100%的数据,保证有 1≤a_0,a_1,b_0,b_1≤2,000,000,0001≤a0​,a1​,b0​,b1​≤2,000,000,000 且 n≤2000n≤2000。

NOIP 2009 提高组 第二题

1、x的质因子的范围

2、别忘了 sqrt(b1)之后还有可能的因子

ll  n,a0,a1,b0,b1;
bool isp[maxn];
ll prime[maxn];
ll cnt=0;
ll gcd(ll a,ll b){
if(b==0)return a;
return gcd(b,a%b);
}
ll lcm(ll a,ll b){
return  a*b/(gcd(a,b));
}
void run(ll x,ll &res,ll k){
res=0;
while(x%k==0){
    res+=1;
    x/=k;
}
}
signed main() {
#ifdef local
    freopen("input2.txt","r",stdin);
#endif //local
    ll shangjie=sqrt(9e9);
    mem(isp,1);
    for(ll i=2;i<=shangjie;i++){
        if(isp[i]){
            prime[cnt++]=i;
            for(ll j=i+i;j<=shangjie;j+=i){
                isp[j]=0;
            }
        }
    }
    cin>>n;
    for(ll i=1;i<=n;i++){
        cin>>a0>>a1>>b0>>b1;
        int tt=sqrt(b1);

        ll ans=1;
        ll b1b1=b1;
        for(ll j=0;j<cnt;j++){
                if(b1b1%prime[j])continue;
                //b1b1%=prime[j];
                ll tem=prime[j];
                while(b1b1%tem==0){
                    b1b1/=tem;
                }
            ll cnta0,cnta1,cntb0,cntb1;
            run(a0,cnta0,tem);
            run(a1,cnta1,tem);
            run(b0,cntb0,tem);
            run(b1,cntb1,tem);
           // cout<<cnta0<<cnta1<<cntb0<<cntb1<<en;
            ll l=0;ll r=inf;
            if(cnta0<cnta1){
                ans=0;
                break;
            }
            if(cnta0==cnta1){
                l=max(l,cnta1);
            }
            if(cnta0>cnta1){
                r=min(r,cnta1);
                l=max(l,cnta1);
            }
            if(cntb0>cntb1){
                ans=0;
                break;
            }

            if(cntb0==cntb1){
                r=min(r,cntb1);
            }
            if(cntb0<cntb1){
                l=max(l,cntb1);
                r=min(r,cntb1);
            }
            if(l>r){
                ans=0;
                break;
            }else{
            ans*=(r-l+1);
            }
        }
        if(b1b1!=1){
                ll tem=b1b1;
//                while(b1b1%tem==0){
//                    b1b1/=tem;
//                }
            ll cnta0,cnta1,cntb0,cntb1;
            run(a0,cnta0,tem);
            run(a1,cnta1,tem);
            run(b0,cntb0,tem);
            run(b1,cntb1,tem);
          //  cout<<cnta0<<cnta1<<cntb0<<cntb1<<en;
            ll l=0;ll r=inf;
            if(cnta0<cnta1){
                ans=0;
                break;
            }
            if(cnta0==cnta1){
                l=max(l,cnta1);
            }
            if(cnta0>cnta1){
                r=min(r,cnta1);
                l=max(l,cnta1);
            }
            if(cntb0>cntb1){
                ans=0;
                break;
            }

            if(cntb0==cntb1){
                r=min(r,cntb1);
            }
            if(cntb0<cntb1){
                l=max(l,cntb1);
                r=min(r,cntb1);
            }
            //cout<<tem<<' '<<l<<' '<<r<<en;
            if(l>r){
                ans=0;
                break;
            }else{
            ans*=(r-l+1);
            }

        }

        cout<<ans<<en;
    }
//cout<<res<<en;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值