Educational Codeforces Round 106 (Rated for Div. 2) D(数论,质数筛)

D. The Number of Pairs

c⋅lcm(a,b)−d⋅gcd(a,b)=x.

由于lcm是gcd的倍数。则x也是gcd的倍数

由上式可得lcm(a,b)= (x+d*gcd(a,b))/c.

故x+d*gcd(a,b)是c的倍数。

故遍历1~sqrt(x),若该数能被x整除,则该数和x/该数都列为gcd的可能对象。再将gcd代入(x+d*gcd(a,b))中,若能整除c,则能得到一对lcm和gcd。

那么问题就变成了已知lcm和gcd。求一对数有多少种可能。

设a=p1*p2*p3,b=p1*p2*p4.那么

lcm=p1*p2*p3*p4*p5,gcd=p1*p2

则lcm/gcd=p3*p4.他们分别可以处于a或者b。也就是说关于a,b的组成一共有2^2次种。需要注意的是如果lcm/gcd=p3*p3*p4这种,种数也还是2^2次种。因为p3*p3肯定是一起出现在a或者b中。不然的话gcd中就会出现p3同时会被lcm除掉。因此我们只需要计算lcm/gcd中质因数出现的种数,再将他作为2的指数即可。对于求质因数的种数,我们可以利用埃氏筛。埃氏筛相交于线性筛的缺点就是同一个数会被他的不同质因子都检索到,但这恰好是我们所需要的特性。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e7;
int r[MAXN+50]; //记录每个数字的质因子种类数
void init(){
    for(int i=2;i<=MAXN;i++)
        if(!r[i]){ //判断i是否为素数
            for(int j=i;j<=MAXN;j+=i)
                r[j]++; //i在范围内的倍数的质因子种类数++
        }
}
ll c,d,x,ans;
void add(int gcd){
    ll lcm=x+d*gcd;
    if(lcm%c==0){
        lcm/=c;
        if(lcm%gcd==0)
            ans+=1LL<<r[lcm/gcd];
    }
}
void solve(){
    ans=0;
    cin>>c>>d>>x;
    int s=sqrt(x);
    for(int i=1;i<=s;i++){
        if(x%i==0){ //枚举x的因子i
            add(i);
            if(i*i!=x)
                add(x/i);
        }
    }
    cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    init();
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

 

posted @ 2021-03-25 21:36  mikku  阅读(41)  评论(0)    收藏  举报