LOJ2185 约数个数和 数列
LOJ2185 约数个数和 数列
题意
求
\[\sum_{i=1}^n\sum_{j=1}^m d(ij) ,d(x)表示x的约数个数\\
n,m \leq 5e4
\]
分析
\[d(ij) = \sum_{x|i}\sum_{y|j} [(x,y) = 1]
\]
\[ans = \sum\sum d(ij)\\
=\sum \sum \sum_{x|i} \sum_{y|j} [(x,y) = 1]\\
=\sum_{x=1}^n \sum_{y=1}^m \lfloor \frac{n}{x} \rfloor \lfloor \frac{m}{y}\rfloor \sum_{d|x,d|y} \mu(d)\\
= \sum_{d = 1}^{min(n,m)} \mu(d) \sum_{i=1}^{\lfloor \frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \lfloor \frac{n}{id}\rfloor \lfloor \frac{m}{id}\rfloor\\
= \sum_{d=1}^{min(n,m)} \mu(d) \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \lfloor \frac{n}{id} \rfloor \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} \lfloor \frac{m}{id} \rfloor \\
= \sum_{d=1}^{min(n,m)} \mu(d) t(\lfloor \frac{n}{d} \rfloor)t(\lfloor \frac{m}{d} \rfloor)
\]
预处理出\(t\),对原式整除分块即可
复杂度\(O(T\sqrt{n} + n\sqrt{n})\)
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define re register
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 1e9 + 7;
const int maxn = 5e4 + 5;
ll rd(){
ll x = 0;
int f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll t[maxn];
int prime[maxn], prime_tot;
int is_prime[maxn];
int mu[maxn];
void pre_calc(int lim) {
mu[1] = 1;
for (int i = 2; i <= lim; i++) {
if (!is_prime[i]) {
prime[++prime_tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= prime_tot; j++) {
if (i * prime[j] > lim) break;
is_prime[i * prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
else mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1;i <= lim;i++)
mu[i] += mu[i - 1];
}
int main(){
pre_calc(maxn - 3);
for(int i = 1;i <= maxn - 5;i++){
for(int j = 1,k;j <= i;j = k + 1) {
k = i / (i / j);
t[i] += (ll)(i / j) * (k - j + 1);
}
}
int T = rd();
while(T--){
int n = rd();
int m = rd();
int nn = min(n,m);
ll ans = 0;
for(int i = 1,j;i <= nn;i = j + 1) {
j = min(n / (n / i),m / (m / i));
ans += (ll)t[n / i] * t[m / i] * (mu[j] - mu[i - 1]);
}
cout << ans << '\n';
}
}