Codeforces 1499D - The Number of Pairs (数学)

Educational Codeforces Round 106 (Rated for Div. 2) D. The Number of Pairs


题意

给定三个正整数\(c,d,x\),询问有多少对正整数对\((a,b)\),满足

\[c \cdot lcm - d \cdot gcd = x \]

限制

\(1\le T\le 10^4\)

\(1\le c,d,x\le 10^7\)




思路

对于原式

\[c \cdot lcm - d \cdot gcd = x \]

\(gcd\)\(lcm\)的数学性质,很容易得到一个结论:\(lcm\)定是\(gcd\)的倍数

那么便能将上式化为

\[lcm=\frac{x+d\cdot gcd}{c} \]

右侧定是一个整数,即\(x+d\cdot gcd\)定是\(c\)的倍数

那么我们可以\(O(\sqrt x)\)枚举\(x\)的所有因子作为\(gcd\)

由于\(c,d,x\)已知,在满足上述条件的前提下,可通过\(gcd,c,d,x\)直接计算出所匹配的\(lcm\)

问题现在便转化成了“在已知\(gcd\)\(lcm\)的前提下求有多少对整数对满足条件”


从数学角度可知

\(gcd(a,b)\)\(a,b\)的质因子的交集

\(lcm(a,b)\)\(a,b\)的质因子的并集

那么\(\frac{lcm}{gcd}\)便是多出来的质因子的乘积

对于\(\frac{lcm}{gcd}\)每种质因子,不论数量,都应该全数位于\(\frac{a}{gcd}\)或者全数位于\(\frac{b}{gcd}\)

否则,这些质因子在\(a\)\(b\)中同时出现,便会算在\(gcd\)中,于此时情况不符

所以如果我们想要构造\(a,b\)两个数,每种质因子只能够挑其中一个数乘进去

\(\frac{lcm}{gcd}\)的质因子种类数为\(n\),则能够构造出的整数对共有\(2^n\)


实践可得,在线的质因子分解算法都将会完美地TLE 15

所以考虑离线处理每个数拥有的质因子种类数

写法类似于埃氏素数筛法,详情见代码部分的\(init\)函数

注意\(\frac{\frac{x}{gcd}+d}{c}\)的数据范围最大可能达到\(2\cdot 10^7\)




代码

(1075ms/2000ms)

#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;
}

https://blog.csdn.net/qq_36394234/article/details/114994557

posted @ 2021-03-19 00:57  StelaYuri  阅读(282)  评论(0)    收藏  举报