「BZOJ 3994」「SDOI 2015」约数个数和「莫比乌斯反演」

$d(x)$$x$的约数个数，求$\sum_{i=1}^{n}\sum_{j=1}^{m}d(ij)$

$d(ij) = \sum_{x|i}\sum_{y|j} [gcd(x,y)=1]$

$i=\prod_{k = 1}^{m} p_k{c_k},j=\prod_{k=1}m p_k^{d_k}$

$=\sum_{i = 1}^n \sum_{j = 1}^m \sum_{x|i} \sum_{y|j} [gcd(x, y)=1]$

$=\sum_{x=1}^n \sum_{y=1}^m [gcd(x, y)=1]\lfloor \frac{n}{x}\rfloor\lfloor \frac{m}{y} \rfloor$

$=\sum_{x=1}^n \sum_{y=1}^m (\sum_{d|x,d|y} \mu(d) )\lfloor \frac{n}{x}\rfloor\lfloor \frac{m}{y} \rfloor$

$=\sum_{d=1}^n \mu(d) \sum_{x=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{y=1}^{\lfloor \frac{m}{d} \rfloor} \lfloor \frac{n}{xd} \rfloor \lfloor \frac{m}{xd} \rfloor$

$=\sum_{d=1}^n \mu(d) \sum_{x=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{y=1}^{\lfloor \frac{m}{d} \rfloor} \lfloor \frac{\lfloor\frac{n}{d}\rfloor}{x} \rfloor \lfloor \frac{\lfloor\frac{m}{d}\rfloor}{y} \rfloor$

$f(n)=\sum_{i=1}^n\lfloor \frac{n}{i} \rfloor$，则答案为$\sum_{d=1}^n \mu(d)f(\lfloor \frac{n}{d} \rfloor) f(\lfloor \frac{m}{d} \rfloor)$

$f(n)=\sum_{i=1}^n d(i)$

#include <algorithm>
#include <cstdio>
using namespace std;

typedef long long ll;

const int N = 5e4 + 10;

ll sum[N], mu[N], d[N];
int p[N], tot, e[N];
bool tag[N];

void init(int n) {
mu[1] = d[1] = 1;
for(int i = 2; i <= n; i ++) {
if(!tag[i]) {
p[tot ++] = i; mu[i] = -1; d[i] = 2; e[i] = 1;
}
for(int j = 0; j < tot && i * p[j] <= n; j ++) {
tag[i * p[j]] = 1;
if(i % p[j] == 0) {
mu[i * p[j]] = 0;
e[i * p[j]] = e[i] + 1;
d[i * p[j]] = d[i] / (e[i] + 1) * (e[i] + 2);
break ;
}
mu[i * p[j]] = - mu[i];
e[i * p[j]] = 1;
d[i * p[j]] = d[i] * 2;
}
mu[i] += mu[i - 1];
d[i] += d[i - 1];
}
}

ll calc(int n, int m) {
ll ans = 0;
for(int i = 1, j; i <= n; i = j + 1) {
j = min(n / (n / i), m / (m / i));
ans += (mu[j] - mu[i - 1]) * d[n / i] * d[m / i];
}
return ans;
}

int main() {
init(50000);
int test; scanf("%d", &test);
for(int n, m; test --; ) {
scanf("%d%d", &n, &m);
if(n > m) swap(n, m);
printf("%lld\n", calc(n, m));
}
return 0;
}


posted @ 2019-02-11 23:15  hfhongzy  阅读(122)  评论(0编辑  收藏  举报