abc 254 d 题解
abc 254 d
题意
给定一个正整数 \(n\),请你求出有多少个数对满足一下条件:
-
\(1 \le i, j \le n\)。
-
\(i \times j\) 是一个完全平方数。
\(1 \le n \le 2 \times 10 ^ 5\)。
思路
暴力
枚举 \(i\) 和 \(j\),判断乘积是否为完全平方数。
时间复杂度为 \(O(n ^ 2)\)。
正解
对于每个 \(i \ (1 \le i \le n)\),令 \(f(i)\) 表示 \(i\) 最大的完全平方数因子。
也就是说,如果 \(i \times j\) 为完全平方数,就说明 \(\frac{i}{f(i)} = \frac{j}{f(j)}\)。
因为 \(i \times j = f(i) \times f(j) \times \frac{i}{f(i)} \times \frac{j}{f(j)}\),而 \(f(i)\) 和 \(f(j)\) 都是完全平方数,那么 \(\frac{i}{f(i)} \times \frac{j}{f(j)}\) 也必须是完全平方数,也就是 \(\frac{i}{f(i)} = \frac{j}{f(j)}\)。
所以做法就是,记录所有 \(\frac{i}{f(i)}\) 出现的数量,再统计答案。
时间复杂度
如果用埃式筛预处理,那么时间复杂度为 \(O(n \times \log n)\)。
如果直接循环找 \(f(i)\),那么时间复杂度为 \(O(n \times \sqrt n)\)。
// 我的是 O(n * sqrt(n))
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, cnt[N];
long long ans;
int f(int i) {
int s = 0;
for (int j = 1; j * j <= i; j++) {
if (i % j == 0) {
int k = i / j;
if (int(sqrt(j)) * int(sqrt(j)) == j) {
s = max(s, j);
}
if (int(sqrt(k)) * int(sqrt(k)) == k) {
s = max(s, k);
}
}
}
return s;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cnt[i / f(i)]++;
}
for (int i = 1; i <= n; i++) {
ans += cnt[i / f(i)];
}
cout << ans;
return 0;
}