[51nod 1238] 最小公倍数之和 V3(杜教筛)

题意

  • a n s = ∑ i = 1 n ∑ j = 1 n lcm(i, j) . ( n ≤ 1 0 10 ) ans=\displaystyle\sum_{i = 1}^n\sum_{j = 1}^n\text{lcm(i, j)}.(n\le10^{10}) ans=i=1nj=1nlcm(i, j).(n1010)

这个题目比公约数那个题麻烦多了,首先还是把这个式子拆成公约数的形式:
a n s = ∑ i = 1 n ∑ j = 1 n i j ( i , j ) a n s = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i j [ ( i , j ) = 1 ] a n s = ∑ d = 1 n d ( 2 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 i i j [ ( i , j ) = 1 ] − [ i = 1 ] ) ans = \sum_{i = 1}^n\sum_{j = 1}^n\frac{ij}{(i,j)} \\ ans = \sum_{d = 1}^nd\sum_{i = 1}^{\lfloor \frac n d \rfloor}\sum_{j = 1}^{\lfloor \frac n d \rfloor}ij[(i,j)=1] \\ ans = \sum_{d = 1}^nd(2\sum_{i = 1}^{\lfloor \frac n d \rfloor}\sum_{j = 1}^i ij[(i,j)=1]-[i=1]) ans=i=1nj=1n(i,j)ijans=d=1ndi=1dnj=1dnij[(i,j)=1]ans=d=1nd(2i=1dnj=1iij[(i,j)=1][i=1])
f ( n ) = ∑ i = 1 n n i [ ( n , i ) = 1 ] f(n)=\displaystyle\sum_{i = 1}^nni[(n,i)=1] f(n)=i=1nni[(n,i)=1],则:
f ( n ) = n ∑ i = 1 n i [ ( n , i ) = 1 ] f ( n ) = n × n ϕ ( n ) + [ n = 1 ] 2 f(n) = n\sum_{i = 1} ^ n i[(n,i)=1]\\ f(n)=n\times\frac{n\phi(n)+[n=1]} 2 f(n)=ni=1ni[(n,i)=1]f(n)=n×2nϕ(n)+[n=1]
现在我们来证明一下 n ϕ ( n ) 2 = ∑ i = 1 n i [ ( n , i ) = 1 ] \frac{n\phi(n)}2=\displaystyle\sum_{i = 1} ^ n i[(n,i)=1] 2nϕ(n)=i=1ni[(n,i)=1],这个实际上就是要我们证明 ( i , n ) = 1 (i,n)=1 (i,n)=1时, ( n − i , n ) = 1 (n-i,n)=1 (ni,n)=1。我们考虑反证法,假设存在 ( i , n ) = 1 (i,n)=1 (i,n)=1 ( n − i , n ) = k ( k > 1 ) (n-i,n)=k(k>1) (ni,n)=k(k>1),那么:
( n − i )  mod k = 0  ① n  mod k = 0  ② (n-i)\text{ mod k = 0}\ ①\\ n\text{ mod k = 0}\ ② (ni) mod k = 0 n mod k = 0 
②式减去①式,可知: i  mod  k = 0 i\text { mod }k = 0 i mod k=0 ( i , n ) = k (i,n)=k (i,n)=k,与假设矛盾,那么 ( i , n ) = 1 (i,n)=1 (i,n)=1时有 ( n − i , n ) = 1 (n-i,n)=1 (ni,n)=1。那么每对互质的数的和都是 n n n,特判一下 n = 1 n=1 n=1的情况就好了,把 f ( n ) f(n) f(n)代回答案式:
a n s = ∑ d = 1 n d ( 2 ∑ i = 1 ⌊ n d ⌋ f ( i ) − [ i = 1 ] ) a n s = ∑ d = 1 n d ( 2 ∑ i = 1 ⌊ n d ⌋ ( i × i ϕ ( i ) + [ i = 1 ] 2 − [ i = 1 ] ) a n s = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ i 2 ϕ ( i ) ans = \sum_{d = 1}^nd(2\sum_{i = 1}^{\lfloor \frac n d \rfloor}f(i)-[i=1])\\ ans = \sum_{d = 1}^nd(2\sum_{i = 1}^{\lfloor \frac n d \rfloor}(i\times\frac{i\phi(i)+[i=1]}2 -[i=1])\\ ans = \sum_{d = 1}^nd\sum_{i = 1}^{\lfloor \frac n d \rfloor}{i^2\phi(i)} ans=d=1nd(2i=1dnf(i)[i=1])ans=d=1nd(2i=1dn(i×2iϕ(i)+[i=1][i=1])ans=d=1ndi=1dni2ϕ(i)
因为 d d d我们可以整除分块,所以我们现在只要求 g ( n ) = i 2 ϕ ( i ) g(n)=i^2\phi(i) g(n)=i2ϕ(i)的前缀和,我们把这个东西卷上个 i d 2 ( x ) id^2(x) id2(x),那么: ( i d 2 ∗ g ) ( n ) = ∑ d ∣ n g ( d ) ( n d ) 2 ( i d 2 ∗ g ) ( n ) = ∑ d ∣ n d 2 ϕ ( d ) ( n d ) 2 ( i d 2 ∗ g ) ( n ) = n 2 ∑ d ∣ n ϕ ( d ) ( i d 2 ∗ g ) ( n ) = n 3 (id^2*g)(n)=\sum_{d | n}g(d)(\frac n d)^2\\(id^2*g)(n)=\sum_{d | n}d^2\phi(d)(\frac n d)^2 \\ (id^2*g)(n)=n^2\sum_{d|n}\phi(d)\\ (id^2*g)(n)=n^3 (id2g)(n)=dng(d)(dn)2(id2g)(n)=dnd2ϕ(d)(dn)2(id2g)(n)=n2dnϕ(d)(id2g)(n)=n3

这就变成了杜教筛的形式,复杂度 O ( n 2 3 ) O(n^{\frac 2 3}) O(n32)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll; 

const int N = 1e6 + 3;
const int mod = 1e9 + 7;
const int inv2 = 500000004;
const int inv6 = 166666668;

int prime[N], notp[N], cnt; 
int phi[N], Sg[N]; 

unordered_map<ll, int> SG;

void Get_Prime(int n) {
	notp[0] = notp[1] = phi[1] = 1; 
	for (int i = 2; i <= n; ++ i) {
		if (!notp[i]) prime[++ cnt] = i, phi[i] = i - 1;
		for (int j = 1; j <= cnt && prime[j] * i <= n; ++ j) {
			notp[prime[j] * i] = 1; 
			phi[prime[j] * i] = 1ll * phi[i] * prime[j] % mod;
			if (!(i % prime[j]))  break;
			(phi[prime[j] * i] += mod - phi[i]) %= mod;
		}
	}
	for (int i = 1; i <= n; ++ i) {
		Sg[i] = (Sg[i - 1] + 1ll * phi[i] * i % mod * i % mod) % mod;
	}
}

int yici(ll x) { return (x % mod + 1) * (x % mod) % mod * inv2 % mod; }
int erci(ll x) { return (x % mod + 1) * (x % mod) % mod * ((x * 2 + 1) % mod) % mod * inv6 % mod; }

int query(ll n) {
	if (n <= 1e6) return Sg[n];
	if (SG[n]) return SG[n];
	int res = 1ll * yici(n) * yici(n) % mod;
	for (ll l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l);
		(res += mod - 1ll * (erci(r) + mod - erci(l - 1)) * query(n / l) % mod) %= mod;
	}
	return SG[n] = res; 
}

int main() {

	ll n, ans = 0; 

	Get_Prime(N - 3);

	cin >> n; 
	for (ll l = 1, r; l <= n; l = r + 1) {
		r = n / (n / l);
		(ans += 1ll * (yici(r) + mod - yici(l - 1)) * query(n / l) % mod) %= mod;
	}
	cout << ans << endl;

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值