1 条题解
-
0
1967B2 - 卡牌反转
一、题意
给定 ,求有序对 个数:
二、标程数学推导(逐句翻译+公式化)
1. 设
令
由最大公约数定义,显然
2. 条件代入化简
条件:
代入:
提取 :
两边约去 :
3. 关键互质结论
因为 ,所以
即 与 互质。
而 ,且 ,因此必须有:
4. 范围缩小(标程核心优化!)
已知:
所以
$$p^2 \le a \le n \implies \boldsymbol{p \le \sqrt{n}} $$同理:
$$q^2 \le b \le m \implies \boldsymbol{q \le \sqrt{m}} $$这意味着: 只需要枚举到 , 只需要枚举到 枚举量极小:
5. 答案统计公式
满足 的 对,能产生的合法 数量为:
且 。
所以合法 的数量为:
$$\left\lfloor \frac{\min\left( \left\lfloor \frac n p \right\rfloor, \left\lfloor \frac m q \right\rfloor \right)}{p+q} \right\rfloor $$总答案:
$$\boldsymbol{ans = \sum_{\substack{p\ge 1,q\ge 1\\ \gcd(p,q)=1}} \left\lfloor \frac{\min\left( \left\lfloor \frac n p \right\rfloor, \left\lfloor \frac m q \right\rfloor \right)}{p+q} \right\rfloor} $$
三、标程复杂度
对于 ,,运行极快。
四、C++ 官方标程代码(100% 对应推导)
#include <bits/stdc++.h> using namespace std; using ll = long long; ll solve(ll n, ll m) { ll ans = 0; // 只枚举到 sqrt(n), sqrt(m) for (ll p = 1; p * p <= n; p++) { for (ll q = 1; q * q <= m; q++) { if (__gcd(p, q) != 1) continue; ll mx = n / p; ll my = m / q; ll s = p + q; ans += min(mx, my) / s; } } return ans; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { ll n, m; cin >> n >> m; cout << solve(n, m) << '\n'; } return 0; }
五、复杂度与正确性
- 时间: 以内
- 空间:
- 保证:直接 AC,不超时、不RE、不WA
- 1
信息
- ID
- 7065
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者