DZY LOVES MATH (莫比乌斯反演)

OK!开始更新莫比乌斯反演

先看了一下数据范围,嗯,根据\(jiry\)老师的真言,我们一定是可以筛一遍然后用根号或者是\(log\)的算法。

题目思路挺简单,就是把原始的式子化成:

\(\sum_{k = 1}^{min(a,b)}(a/k)(b/k) \sum_{d | k} f(d) * \mu (k / d)\)

由于莫反的函数是建立在积性上的,但是后面那个显然不是积性。

我们考虑把后面的式子代换一下:\(g(n) = \sum_{d|n}f(n/d) * \mu(d)\)

考虑\(\mu\)这个函数,当\(x > 0\)是1,否则是0.

我们只考虑1的情况,如果是1它就只能是\(d = \prod_{p_i | d} p_i\)

\(k = (d的条件)^r\)时,\(g\)函数不为0.

此时\(g(n) = -\mu(\prod p_i)\)

然后考虑线性筛法求出\(g\)即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
inline int read () {
	int q=0,f=1;char ch = getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;ch=getchar();
	}
	while(isdigit(ch)){
		q=q*10+ch-'0';ch=getchar();
	}
	return q*f;
}
ll ans;
const int maxn = 10000008;
int prime[maxn];
bool is_prime[maxn];
int cnt;
int miu[maxn];
inline void init () {
	cnt = 0;
	memset(prime,0,sizeof(prime));
	memset(is_prime,0,sizeof(is_prime));
	miu[1] = 1;
	for(int i = 2;i < maxn; ++i) {
		if(!is_prime[i]) {
			prime[++cnt] = i;
			miu[i] = -1;
		}
		for(int j = 1;j <= cnt; ++j) {
			if(i * prime[j] >= maxn) {
				break;
			}
			else {
				is_prime[i * prime[j]] = 1;
				if(i % prime[j]) {
					miu[i * prime[j]] = -miu[i];
				}
				else {
					miu[i * prime[j]] = 0;
					break;
				}
			}
		}
	}
//	cout<<1<<endl;
}
int g[maxn];
inline void calc () {
	init();
	g[0] = g[1] = 0;
	for(ll i = 2;i < maxn; ++i) {
		if(miu[i]) {
			for(ll j = i;j < maxn; j *= i) {
				g[j] = -miu[i];
			}
		}
	}
	for(ll i = 2;i < maxn; ++i) {
		g[i] += g[i - 1];
	}
//	cout<<1<<endl;
}
int T;
int main () {
	calc();
	T = read();
	while(T--) {
		int n = read(),m = read();
		if(n > m) swap(n,m);
		ans = 0;
		for(int i = 1,j;i <= n;i = j + 1) {
			j = min(n / (n / i),m / (m / i));
			ans += (ll)(n / i) * (m / i) * ( g[j] - g[i - 1] );
		}
		printf("%lld\n",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/akoasm/p/9741154.html