题目相当于求:
(sum_{a=1}^nsum_{n=1}^m [ab是完全平方数])
如何统计,考虑枚举(a,b)的共有的指数为奇数的质因子的乘积(d)
(sum_{d=1}^n mu^2(d) sqrt{n/d}*sqrt{m/d})
对(sqrt{n/d}*sqrt{m/d})分块,现在要求(mu^2)的前缀和
(sum_{i=1}^n mu^2(i) = sum_{i=1}^{sqrt n} mu(i)*(n/i/i))
证明就是(sum_{d|n}mu(d)=[n=1])
预处理(mu)的前缀和之后,这个同样可以分块求,(n/i/i)只有(n^{1/3})种不同取值。
这样有95分,考虑再处理(sqrt n内的mu^2)的前缀和,就可以100分了,注意空间问题
据官方题解的积分,复杂度是(O(sqrt n))。
复杂度瓶颈在预处理,考虑(mu)不预处理那么多,剩下的一点用杜教筛求,这样可以更快,不写了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;
const int N = 122474500;
int mu[N], s[N];
int p[7000000], p0;
ll n, m, sq;
void sieve(int n) {
fo(i, 2, n) {
if(!s[i]) p[++ p0] = i, mu[i] = -1;
for(int j = 1; i * p[j] <= n; j ++) {
int k = i * p[j];
s[k] = 1;
if(i % p[j] == 0) { mu[k] = 0; break;}
mu[k] = -mu[i];
}
}
mu[1] = 1;
fo(i, 1, n) s[i] = s[i - 1] + (mu[i] != 0), mu[i] += mu[i - 1];
}
int cc = 0;
ll calc(ll n) {
if(n <= sq) return s[n];
int m = sqrt(n);
ll s = 0;
for(int i = 1, j; i <= m; i = j + 1) {
ll x = n / i / i;
j = sqrt(n / x);
s += (mu[j] - mu[i - 1]) * x;
}
return s;
}
int main() {
scanf("%lld %lld", &n, &m);
if(n > m) swap(n, m);
sq = sqrt(n);
sieve(sq);
ll v1 = 0, ans = 0;
for(ll i = 1, j; i <= n; i = j + 1) {
ll x = sqrt(n / i), y = sqrt(m / i);
j = n / x / x;
j = min(j, m / y / y);
ll v2 = calc(j);
ans += (v2 - v1) * x * y;
v1 = v2;
}
pp("%lld
", ans);
}