bzoj 4659 Lcm 莫比乌斯反演

题面

题目传送门

解法

还是写得详细一点比较好

  • 我们可以比较显然地得出式子: ∑ i = 1 n ∑ j = 1 n μ ( g c d ( i , j ) ) 2 l c m ( i , j ) \sum_{i=1}^n\sum_{j=1}^n\mu(gcd(i,j))^2lcm(i,j) i=1nj=1nμ(gcd(i,j))2lcm(i,j)
  • 然后下面就是推导过程了:
    = ∑ d = 1 n μ ( d ) 2 d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ g c d ( i , j ) = = 1 ] i j =\sum_{d=1}^n\mu(d)^2d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)==1]ij =d=1nμ(d)2di=1dnj=1dn[gcd(i,j)==1]ij
  • 通过反演,我们可以得到下面的式子:
    = ∑ d = 1 n μ ( d ) 2 d ∑ d 1 ⌊ n d ⌋ μ ( d 1 ) d 1 2 ∑ i = 1 ⌊ n d d 1 ⌋ ∑ j = 1 ⌊ n d d 1 ⌋ i j =\sum_{d=1}^n\mu(d)^2d\sum_{d_1}^{\lfloor\frac{n}{d}\rfloor}\mu(d_1)d_1^2\sum_{i=1}^{\lfloor\frac{n}{dd_1}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{dd_1}\rfloor}ij =d=1nμ(d)2dd1dnμ(d1)d12i=1dd1nj=1dd1nij
  • 那么我们令 s ( n ) = ∑ i = 1 n i s(n)=\sum_{i=1}^n i s(n)=i=1ni,就可以得到下面的式子:
    = ∑ d = 1 n μ ( d ) 2 d ∑ d 1 ⌊ n d d 1 ⌋ μ ( d 1 ) d 1 2 ∗ s ( ⌊ n d d 1 ⌋ ) 2 =\sum_{d=1}^n\mu(d)^2d\sum_{d_1}^{\lfloor\frac{n}{dd_1}\rfloor}\mu(d_1)d_1^2*s(\lfloor\frac{n}{dd_1}\rfloor)^2 =d=1nμ(d)2dd1dd1nμ(d1)d12s(dd1n)2
  • 然后枚举 d d 1 = k dd_1=k dd1=k,可以得到:
    = ∑ k = 1 n s ( ⌊ n k ⌋ ) 2 ∑ d ∣ k μ ( d ) 2 d ∗ μ ( k d ) ( k d ) 2 =\sum_{k=1}^ns(\lfloor\frac{n}{k}\rfloor)^2\sum_{d|k}\mu(d)^2d*\mu(\frac{k}{d})(\frac{k}{d})^2 =k=1ns(kn)2dkμ(d)2dμ(dk)(dk)2
  • 我们令 f ( k ) = ∑ d ∣ k μ ( d ) 2 d ∗ μ ( k d ) ( k d ) 2 f(k)=\sum_{d|k}\mu(d)^2d*\mu(\frac{k}{d})(\frac{k}{d})^2 f(k)=dkμ(d)2dμ(dk)(dk)2,因为 n ≤ 4 ∗ 1 0 6 n\leq 4*10^6 n4106,所以使用 O ( n log ⁡ n ) O(n\log n) O(nlogn)的筛法是不能通过的。
  • 那么我们考虑如何线性筛这个函数 f ( k ) f(k) f(k)。设 k = p 1 k 1 … p m k m k=p_1^{k_1}\dots p_m^{k_m} k=p1k1pmkm,显然,如果 ∃ k i > 2 \exist k_i>2 ki>2,那么 f ( k ) = 0 f(k)=0 f(k)=0
  • 可以发现, f f f是一个积性函数。那么我们只要处理出 f ( p k ) f(p^k) f(pk)即可
  • 因为 k ≤ 2 k\leq 2 k2,所以我们对于 k = 1 / 2 k=1/2 k=1/2分别讨论
  • 显然可以发现, f ( p ) = − p 2 + p , f ( p 2 ) = − p 3 f(p)=-p^2+p,f(p^2)=-p^3 f(p)=p2+p,f(p2)=p3,所以我们是可以线性筛的。
  • 时间复杂度: O ( n + T n ) O(n+T\sqrt n) O(n+Tn )
  • 因为是对 2 30 2^{30} 230取模,所以我们可以直接自然溢出,然后 & ( 2 30 − 1 ) \&(2^{30}-1) &(2301)即可。

代码

#include <bits/stdc++.h>
#define Mod ((1 << 30) - 1)
#define N 4000010
using namespace std;
template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;}
template <typename T> void chkmin(T &x, T y) {x = x > y ? y : x;}
template <typename T> void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
bool f[N]; int g[N], p[N], mx[N], mns[N], tmp[N];
int s(int n) {return n * (n + 1) / 2;}
void add(int &x, int y) {x += y;}
void sieve(int n) {
	memset(f, true, sizeof(f)); int len = 0; g[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (f[i]) {
			p[++len] = i, g[i] = i - 1ll * i * i;
			mns[i] = mx[i] = tmp[i] = 1;
		}
		for (int j = 1; j <= len && i * p[j] <= n; j++) {
			int k = i * p[j]; f[k] = false;
			if (i % p[j] == 0) {
				tmp[k] = tmp[i], mns[k] = mns[i] + 1;
				mx[k] = max(mx[tmp[k]], mns[k]);
				if (mx[k] > 2) {g[k] = 0; continue;}
				g[k] = g[tmp[k]] * (-p[j] * p[j] * p[j]);
				break;
			} else {
				tmp[k] = i, mns[k] = 1, mx[k] = max(mx[i], 1);
				if (mx[k] > 2) {g[k] = 0; continue;}
				g[k] = g[i] * (p[j] - p[j] * p[j]);
			}
		}
	}
	for (int i = 1; i <= n; i++) g[i] += g[i - 1];
}
int solve(int n, int m) {
	int ret = 0, x = 0;
	for (int i = 1; i <= n; i = x + 1) {
		x = min(n / (n / i), m / (m / i));
		add(ret, (g[x] - g[i - 1]) * s(n / i) * s(m / i));
	}
	return ret & Mod;
}
int main() {
	sieve(4e6); int T; read(T);
	while (T--) {
		int n, m; read(n), read(m);
		if (n > m) swap(n, m);
		cout << solve(n, m) << "\n";
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值