一道莫比乌斯反演

∑ i = 1 N ∑ j = 1 M d ( i j ) \sum_{i = 1}^{N} \sum_{j = 1}^{M} d(ij) i=1Nj=1Md(ij)

// d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = 1 ] d(ij) =\sum_{x|i} \sum_{y |j} [(x, y) = 1] d(ij)=xiyj[(x,y)=1]

F ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ n ∣ ( x , y ) ] F(n) = \sum_{i = 1}^{N} \sum_{j= 1}^{M} \sum_{x|i}\sum_{y|j} [n|(x,y)] F(n)=i=1Nj=1Mxiyj[n(x,y)]

f ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = n ] f(n) = \sum_{i = 1}^{N} \sum_{j= 1}^{M} \sum_{x|i}\sum_{y|j} [(x,y) = n] f(n)=i=1Nj=1Mxiyj[(x,y)=n]

F ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ n ∣ ( x , y ) ] = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ [ n ∣ ( x , y ) ] = ∑ x ′ N n ∑ y ′ M n ⌊ N x ′ n ⌋ ⌊ M y ′ n ⌋ F(n) = \sum_{i = 1}^{N} \sum_{j= 1}^{M} \sum_{x|i}\sum_{y|j} [n|(x,y)] = \sum_{x = 1}^{N} \sum_{y = 1}^{M} \lfloor \frac{N}{x} \rfloor \lfloor \frac{M}{y} \rfloor [n|(x, y)] = \sum_{x'}^{\frac{N}{n}} \sum_{y'}^{\frac{M}{n}} \lfloor \frac{N}{x'n} \rfloor \lfloor \frac{M}{y'n} \rfloor F(n)=i=1Nj=1Mxiyj[n(x,y)]=x=1Ny=1MxNyM[n(x,y)]=xnNynMxnNynM

两次整数分块
这道题甚至全longlong也会超时…

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 50010;

int primes[N], cnt, mu[N], sum[N], h[N];
bool st[N];

inline int g(int n, int x) {
    
    
	return n / (n / x);
}

void init() {
    
    
	mu[1] = 1;
	for(int i = 2; i < N; ++i) {
    
    
		if(!st[i]){
    
    
			primes[cnt++] = i;
			mu[i] = -1;
		}
		for(int j = 0; primes[j] * i < N; ++j) {
    
    
			st[primes[j] * i] = 1;
			if(i % primes[j] == 0) break;
			mu[primes[j] * i] = -mu[i];
		}
		
		
	}
	
	for(int i = 1; i < N; ++ i) {
    
    
		sum[i] = sum[i - 1] + mu[i]; 
	}
		
	for(int i = 1; i < N; ++i) {
    
    
		for(int l = 1, r; l <= i; l = r + 1) {
    
    
			r = min(i, g(i, l));
			h[i] += (r - l + 1) * (i / l);
		}
	}
}

int main() {
    
    
	//ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); 
	init();
	
	int T;
	scanf("%d", &T);
	while(T--) {
    
    
		int n, m;
		scanf("%d %d", &n, &m);
		ll res = 0;
		int k = min(n, m);
		for(int l = 1, r; l <= k; l = r + 1) {
    
    
			r = min(k, min(g(n, l), g(m, l)));
			res += (ll)(sum[r] - sum[l - 1]) * h[n / l] * h[m / l];
		}
	    printf("%lld\n", res);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39602052/article/details/113246011
今日推荐