51nod1584 加权约数和 (莫比乌斯反演)

传送门

如果求出 f ( n ) = i j i i σ ( i j ) , g ( n ) = i i σ ( i 2 ) f(n)=\sum_i\sum_{j\le i}i*\sigma(ij),g(n)=\sum_i i*\sigma(i^2)
那么 2 f ( n ) g ( n ) 2*f(n)-g(n) 就是答案

有一个结论是
σ 0 ( i j ) = d i l j [ g c d ( d , l ) = 1 ] \sigma_0(ij)=\sum_{d|i}\sum_{l|j}[gcd(d,l)=1]
证明(口胡):考虑某一个质因子 p p ,假设最后在约数中为 p c p^c
令如果 p p i i 中为 p a p^a ,如果 c a c\le a 那么我们在 i i 中填上 c c ,否则在 j j 中填上 c a c-a
显然 p p 只会在一边出现而且所有的因数考虑完了
如果是 σ ( i j ) \sigma(ij) 的话考虑一下上面的过程想一想最后是什么数,有:
f ( n ) = i = 1 n i j = 1 i p i q j [ g c d ( p , q ) = 1 ] p j q f(n)=\sum_{i=1}^ni\sum_{j=1}^i\sum_{p|i}\sum_{q|j}[gcd(p,q)=1]\frac{pj}{q}
= d = 1 n μ ( d ) d p p p i i d q d j , j i j q =\sum_{d=1}^{n}\mu(d)\sum_{d|p}p\sum_{p|i}i\sum_{d|q}\sum_{d|j,j\le i}\frac{j}{q}
= d = 1 n μ ( d ) p = 1 n / d d p p i , i n / d d i q i q j , j i j q =\sum_{d=1}^{n}\mu(d)\sum_{p=1}^{n/d}dp\sum_{p|i,i\le n/d}di\sum_{q\le i}\sum_{q|j,j\le i}\frac{j}{q}
= d = 1 n μ ( d ) d 2 p = 1 n / d p p i , i n / d i j i σ ( j ) =\sum_{d=1}^{n}\mu(d)d^2\sum_{p=1}^{n/d}p\sum_{p|i,i\le n/d}i\sum_{j\le i}\sigma(j)
= d = 1 n μ ( d ) d 2 i n / d i σ ( i ) j i σ ( j ) =\sum_{d=1}^{n}\mu(d)d^2\sum_{i\le n/d}i*\sigma(i)\sum_{j\le i}\sigma(j)
已经可以 O ( n ) O(n) 预处理, O ( n ) O(\sqrt n) 查询了,但 T T 较大
考虑一个 d , i d,i 的贡献,对所有 n d i n\ge d*i 都有贡献,于是就可以 O ( n l o g n ) O(nlogn) 预处理, O ( 1 ) O(1) 查询
g g 同理
顺带一提, σ \sigma 可以用线性筛,考虑质数次幂的贡献即可
σ ( p ) = p + 1 \sigma(p)=p+1
σ ( p k ) = i = 0 k p k \sigma(p^k)=\sum_{i=0}^kp^k

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int Mod = 1e9 + 7, N = 1e6 + 5;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; } 
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
int T, n, mu[N], sig[N], Ssig[N];
bool isp[N]; int prim[N], tot;
int Mn[N], vlMn[N], ans[N], f[N], g[N];
void prework(){
	n = 1e6;
	mu[1] = sig[1] = 1;
	for(int i = 2; i <= n; i++){
		if(!isp[i]){
			prim[++tot] = i;
			sig[i] = i+1; mu[i] = Mod-1;
			Mn[i] = 1; vlMn[i] = i+1;
		}
		for(int j = 1; j <= tot; j++){
			if(prim[j] * i > n) break;
			int k = prim[j] * i; isp[k] = true;
			if(i % prim[j] == 0){
				Mn[k] = Mn[i]; mu[k] = 0;
				vlMn[k] = add(mul(vlMn[i], prim[j]), 1);
				sig[k] = mul(vlMn[k], sig[Mn[k]]);
				break;
			}
			Mn[k] = i; vlMn[k] = prim[j]+1;
			mu[k] = mul(mu[i], mu[prim[j]]);
			sig[k] = mul(sig[i], sig[prim[j]]);
		}
	}
	for(int i = 1; i <= n; i++){
		f[i] = mul(mu[i], mul(i,i));
		Ssig[i] = add(Ssig[i-1], sig[i]);
		g[i] = mul(mul(i, sig[i]), dec(mul(2,Ssig[i]),sig[i]));
	}
	for(int i = 1; i <= n; i++)
	for(int j = 1, up=n/i; j <= up; j++)
	Add(ans[i*j], mul(f[i],g[j]));
	for(int i = 1; i <= n; i++) Add(ans[i], ans[i-1]);
} 
int main(){
	prework(); 
	cin >> T; for(int i = 1; i <= T; i++){ 
		scanf("%d", &n); cout << "Case #" << i << ": " << ans[n] << '\n'; 
	} return 0;
}
发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/103623846