Loading

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';
	}
}
posted @ 2021-04-06 19:18  MQFLLY  阅读(74)  评论(0编辑  收藏  举报