Codeforces 第942轮[B] Reverse Card (Easy&&HardVersion)题解

题目详情

B1. Reverse Card (Easy Version)

The two versions are different problems. You may want to read both versions. You can make hacks only if both versions are solved.

You are given two positive integers 𝑛, 𝑚.

Calculate the number of ordered pairs (𝑎,𝑏) satisfying the following conditions:

  • 1≤𝑎≤𝑛, 1≤𝑏≤𝑚;
  • 𝑎+𝑏 is a multiple of 𝑏⋅gcd(𝑎,𝑏).

Input

Each test contains multiple test cases. The first line contains the number of test cases 𝑡𝑡 (1≤𝑡≤10^4). The description of the test cases follows.

The first line of each test case contains two integers 𝑛, 𝑚 (1≤𝑛,𝑚≤2⋅10^6).

It is guaranteed that neither the sum of 𝑛𝑛 nor the sum of 𝑚𝑚 over all test cases exceeds 2⋅10^6.

Output

For each test case, print a single integer: the number of valid pairs.

B2. Reverse Card (Hard Version)

The two versions are different problems. You may want to read both versions. You can make hacks only if both versions are solved.

You are given two positive integers 𝑛, 𝑚.

Calculate the number of ordered pairs (𝑎,𝑏) satisfying the following conditions:

  • 1≤𝑎≤𝑛, 1≤𝑏≤𝑚;
  • 𝑏⋅gcd(𝑎,𝑏)is a multiple of 𝑎+𝑏.

Input

Each test contains multiple test cases. The first line contains the number of test cases 𝑡𝑡 (1≤𝑡≤10^4). The description of the test cases follows.

The first line of each test case contains two integers 𝑛𝑛, 𝑚𝑚 (1≤𝑛,𝑚≤2⋅10^6).

It is guaranteed that neither the sum of 𝑛 nor the sum of 𝑚𝑚 over all test cases exceeds 2⋅10^.

Output

For each test case, print a single integer: the number of valid pairs.

重要题干的中文翻译:

B1. Reverse Card (Easy Version)

计算满足以下条件的有序对 (𝑎,𝑏) 的数量:

1≤𝑎≤𝑛, 1≤𝑏≤𝑚;
𝑎+𝑏 是 𝑏⋅gcd(𝑎,𝑏) 的倍数。

B2. Reverse Card (Hard Version)

计算满足以下条件的有序对 (𝑎,𝑏) 的数量:

1≤𝑎≤𝑛, 1≤𝑏≤𝑚;
𝑏⋅gcd(𝑎,𝑏) 是 𝑎+𝑏 的倍数。

解题思路

对于简单版本(B1),我们需要计算满足条件 𝑎+𝑏 是 𝑏⋅gcd(𝑎,𝑏) 的倍数的有序对 (𝑎,𝑏) 的数量。这可以通过枚举所有可能的 𝑎 和 𝑏 的值,然后检查是否满足条件来完成。由于较小的约束条件 (1≤𝑛,𝑚≤2⋅10^6),这种方法是可行的。

而对于困难版本(B2),我们需要计算满足条件 𝑏⋅gcd(𝑎,𝑏) 是 𝑎+𝑏 的倍数的有序对 (𝑎,𝑏) 的数量。这个条件更加复杂,需要一种更巧妙的方法来解决。通常,这种类型的问题可能需要使用数论知识和技巧,例如分析最大公约数和最小公倍数的性质,以及利用模运算来加速计算。

B1. Reverse Card (Easy Version)

\gcd(a,b)定义为d. 假设a=pd以及b=qd,我们知道\gcd(p,q)=1.

(b\cdot\gcd(a,b))\mid (a+b)\iff (qd^2)\mid (pd+qd)\iff (qd)\mid (p+q)所以我们就可以假设q+p = k\cdot qd,则p=(kd-1)q。因为gcd(q,p) = 1它们的最大公约数为1,此时kd-1不一定总为1,所以可知在此处q=1

将d从1遍历至m,我们知道p + 1 = kd \leq \left \lfloor \frac{n}{d} \right \rfloor + 1,所以我们把\left\lfloor\frac{\min\{\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{q}\rfloor\}}{p+q}\right\rfloor加入到答案中。

在这个方式下p=0,k=1,d=1都已经包含在这个答案中,所以我们需要在ans的最后减一才是最终的答案。

时间复杂度:\mathcal O(\sum m)

B2. Reverse Card (Hard Version)

\gcd(a,b)定义为d. 假设a=pd以及b=qd,我们知道\gcd(p,q)=1.所以易知下式:

(a+b)\mid (b\cdot\gcd(a,b))\iff (pd+qd)\mid (qd^2)\iff (p+q)\mid (qd)

我们知道\gcd(p+q,q)=\gcd(p,q)=1, 所以(p+q)\mid d

p\ge 1,q\ge 1, 所以p < d=\frac{a}{p}\le \frac{n}{p},因此p^2 < n. 由此易知q^2 < m

所以(p,q)是\mathcal O(\sqrt{nm})=\mathcal O(n+m). 我们可以遍历(p,q),并在gcd(p,q)=1的情况下计算答案。此时(p+q)\mid d的条件就满足了, 所以我们往答案里添加 \left\lfloor\frac{\min\{\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{q}\rfloor\}}{p+q}\right\rfloor

时间复杂度:\mathcal O(\sum n + \sum m)

代码

B1. Reverse Card (Easy Version)

#include <iostream>

using namespace std;
typedef long long ll;
const int N = 2000005;

int tc,n,m;
ll ans;

void solve() {
    cin >> n >> m;
    ans = 0;
    for (int i=1 ;i <= m ; i++) {
        ans += (n+i)/(1ll*i*i);
        
    }
    cout<<ans-1<<'\n';
}

int main() {
    cin>>tc; 
    while(tc--) 
        solve();

}

B2. Reverse Card (Hard Version)

#include <bits/stdc++.h>
using namespace std;
 
#define nl "\n"
#define nf endl
#define ll long long
#define pb push_back
#define _ << ' ' <<
 
#define INF (ll)1e18
#define mod 998244353
#define maxn 110
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
 
    #if !ONLINE_JUDGE && !EVAL
        ifstream cin("input.txt");
        ofstream cout("output.txt");
    #endif
    int t;
    cin>>t;
    while(t--)
    {
        ll n,m; cin >> n>>m;
        ll sq = sqrt(n) + 2,sqm=sqrt(m)+2;
    
        vector bad(sq + 1, vector<bool>(sqm+1, 0));
        for (ll i = 2; i <= min(sq,sqm); i++) {
            for (ll a = i; a <= sq; a += i) {
                for (ll b = i; b <= sqm; b += i) {
                    bad[a][b] = true;
                }
            }
        }
    
        ll ans = 0;
        for (ll a = 1; a * a <= n; a++) {
            for (ll b = 1; b * b <= m; b++) {
                if (bad[a][b]) continue;
                ans += min(n/(a+b)/a,m/(a+b)/b);
            }
        }
        cout << ans << nl;
    }
 
    return 0;
}

  • 36
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值