Codeforces Round 942 (Div. 2) D2. Reverse Card (Hard Version) 题解 数论

D2. Reverse Card (Hard Version)

题目描述

给你两个正整数 n n n m m m

请计算满足以下条件的有序数对 ( a , b ) (a, b) (a,b) 的个数:

  • 1 ≤ a ≤ n 1\le a\le n 1an , 1 ≤ b ≤ m 1\le b\le m 1bm ;
  • b ⋅ gcd ⁡ ( a , b ) b \cdot \gcd(a,b) bgcd(a,b) a + b a+b a+b 的倍数。

输入描述

每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 1 0 4 1\le t\le 10^4 1t104 )。测试用例说明如下。

每个测试用例的第一行包含两个整数 n n n , m m m ( 1 ≤ n , m ≤ 2 ⋅ 1 0 6 1\le n,m\le 2 \cdot 10^6 1n,m2106 )。

保证所有测试用例中 n n n m m m 的总和不超过 2 ⋅ 1 0 6 2 \cdot 10^6 2106

输出描述

为每个测试用例打印一个整数:有效配对的数量。

样例输入

6
1 1
2 3
3 5
10 8
100 1233
1000000 1145141

样例输出

0
1
1
6
423
5933961

原题

CF——传送门

思路

CF题解——传送门
gcd ⁡ ( a , b ) = d \gcd(a,b)=d gcd(a,b)=d ,则 a = p d a=pd a=pd b = q d b=qd b=qd ,所以 gcd ⁡ ( p , q ) = 1 \gcd(p,q)=1 gcd(p,q)=1 。于是条件可等价推导: ( a + b ) ∣ ( b ⋅ gcd ⁡ ( a , b ) )    ⟺    ( p d + q d ) ∣ ( q d 2 )    ⟺    ( p + q ) ∣ ( q d ) (a+b)\mid (b\cdot\gcd(a,b))\iff (pd+qd)\mid (qd^2)\iff (p+q)\mid (qd) (a+b)(bgcd(a,b))(pd+qd)(qd2)(p+q)(qd) 。又因为 gcd ⁡ ( p + q , q ) = gcd ⁡ ( p , q ) = 1 \gcd(p+q,q)=\gcd(p,q)=1 gcd(p+q,q)=gcd(p,q)=1 ,所以 ( p + q ) ∤ q (p+q) \nmid q (p+q)q,所以 ( p + q ) ∣ d (p+q)\mid d (p+q)d 。此外,因为 p ≥ 1 , q ≥ 1 p\ge 1,q\ge 1 p1,q1 p < d = a p ≤ n p p < d=\frac{a}{p}\le \frac{n}{p} p<d=papn ,所以 p 2 < n p^2 < n p2<n 。同理, q 2 < m q^2 < m q2<m 。所以 ( p , q ) (p,q) (p,q) 的个数是 O ( n m ) = O ( n + m ) \mathcal O(\sqrt{nm})=\mathcal O(n+m) O(nm )=O(n+m) 。所以可以枚举 gcd ⁡ ( p , q ) = 1 \gcd(p,q)=1 gcd(p,q)=1 的每个 ( p , q ) (p,q) (p,q) ,找出其中满足 ( p + q ) ∣ d (p+q)\mid d (p+q)d 的序对,即加上 ⌊ min ⁡ { ⌊ n p ⌋ , ⌊ m q ⌋ } p + q ⌋ \left\lfloor\frac{\min\{\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{q}\rfloor\}}{p+q}\right\rfloor p+qmin{⌊pn,qm⌋}

PS:这场Div.2的C题被Hack了,由于二分查找上界写小了。所以我很难过。 所以以后要注意仔细想一下边界,不要想当然了()。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;
    while (t--)
    {
        ll n, m;
        cin >> n >> m;

        ll maxp = sqrt(n) + 6;
        ll maxq = sqrt(m) + 6;
        vector<vector<bool>> not_gcd_equal_to_1(maxp + 1, vector<bool>(maxq + 1, 0));
        // 预处理所有gcd(p,q)≠1的序对
        for (ll k = 2; k <= min(maxp, maxq); k++)
        {
            for (ll i = k; i <= maxp; i += k)
            {
                for (ll j = k; j <= maxq; j += k)
                {
                    not_gcd_equal_to_1[i][j] = 1;
                }
            }
        }
        ll ans = 0;
        for (ll p = 1; p * p <= n; p++)
        {
            for (ll q = 1; q * q <= m; q++)
            {
                if (!not_gcd_equal_to_1[p][q])
                {
                    ans += min(n / p / (p + q), m / q / (p + q));
                }
            }
        }
        cout << ans << '\n';
    }

    return 0;
}
  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值