51nod1220 约数之和 杜教筛

因为 d ( i j ) = ∑ p ∣ i ∑ q ∣ i [ ( p , q ) = = 1 ] p j q d(ij) = \sum_{p | i} \sum_{q | i} [(p, q) == 1] \frac{pj}{q} d(ij)=piqi[(p,q)==1]qpj
那么
∑ i = 1 n ∑ j = 1 n d ( i ∗ j ) \sum_{i = 1}^n \sum_{j = 1}^n d(i * j) i=1nj=1nd(ij)
= ∑ i = 1 n ∑ j = 1 n ∑ p ∣ i ∑ q ∣ i [ ( p , q ) = = 1 ] p j q = \sum_{i = 1}^n \sum_{j = 1}^n \sum_{p | i} \sum_{q | i} [(p, q) == 1] \frac{pj}{q} =i=1nj=1npiqi[(p,q)==1]qpj
对式子大力莫反,有
= ∑ d = 1 n μ [ d ] ∑ i = 1 n ∑ j = 1 n ∑ p ∣ i ∑ q ∣ i [ d ∣ ( p , q ) ] p j q = \sum_{d = 1}^n \mu[d] \sum_{i = 1}^n \sum_{j = 1}^n \sum_{p | i} \sum_{q | i} [d | (p, q)] \frac{pj}{q} =d=1nμ[d]i=1nj=1npiqi[d(p,q)]qpj
再化简一下,就是
= ∑ d = 1 n μ [ d ] ∑ d ∣ p p ∑ d ∣ q 1 q ∑ p ∣ i ∑ q ∣ j j = \sum_{d = 1}^n \mu[d] \sum_{d | p} p \sum_{d | q} \frac{1}{q} \sum_{p | i} \sum_{q | j} j =d=1nμ[d]dppdqq1piqjj
也就是
∑ d = 1 n μ [ d ] ∗ d ( ∑ p = 1 [ n d ] p ∗ [ [ n d ] p ] ) ( 1 2 ∑ q = 1 [ n d ] [ [ n d ] p ] ( [ [ n d ] p ] + 1 ) ) \sum_{d = 1}^n \mu[d] * d (\sum_{p = 1}^{[\frac{n}{d}]} p * [\frac{[\frac{n}{d}]}{p}]) (\frac{1}{2} \sum_{q = 1}^{[\frac{n}{d}]} [\frac{[\frac{n}{d}]}{p}]( [\frac{[\frac{n}{d}]}{p}] + 1)) d=1nμ[d]d(p=1[dn]p[p[dn]])(21q=1[dn][p[dn]]([p[dn]]+1))

观察一下两个括号里面的东西
会发现实际上就是
∑ i = 1 n i ∗ [ n i ] \sum_{i = 1}^n i * [\frac{n}{i}] i=1ni[in] ∑ i = 1 n [ n i ] ( [ n i ] + 1 ) 2 \sum_{i = 1}^n \frac{[\frac{n}{i}]([\frac{n}{i}] + 1)}{2} i=1n2[in]([in]+1)
前面那个肯定有 ∑ i = 1 n i ∗ [ n i ] = ∑ i = 1 n d ( i ) \sum_{i = 1}^n i * [\frac{n}{i}] = \sum_{i = 1}^n d(i) i=1ni[in]=i=1nd(i)
后面那个我们换一下形式,会发现是
∑ i = 1 n [ n i ] ( [ n i ] + 1 ) 2 = ∑ i = 1 n ∑ j = 1 [ n i ] j \sum_{i = 1}^n \frac{[\frac{n}{i}]([\frac{n}{i}] + 1)}{2} = \sum_{i = 1}^n \sum_{j = 1}^{[\frac{n}{i}]} j i=1n2[in]([in]+1)=i=1nj=1[in]j
也就是
= ∑ j = 1 n j ∑ i = 1 [ n j ] 1 = ∑ j = 1 n j [ n j ] =\sum_{j = 1}^n j \sum_{i = 1}^{[\frac{n}{j}]} 1 = \sum_{j = 1}^n j [\frac{n}{j}] =j=1nji=1[jn]1=j=1nj[jn]
所以整个式子就是
∑ d = 1 n d ∗ μ [ d ] ( ∑ i = 1 [ n d ] d ( i ) ) 2 \sum_{d = 1}^n d * \mu[d] (\sum_{i = 1}^{[\frac{n}{d}]} d(i)) ^ 2 d=1ndμ[d](i=1[dn]d(i))2
那么前面的东西我们卷上 i d id id然后杜教筛,后面的东西我们可以先处理一下前 n 2 / 3 n^{2/3} n2/3 d ( i ) d(i) d(i),对于后面的那些我们可以直接利用 ∑ i = 1 n i ∗ [ n i ] \sum_{i = 1}^n i * [\frac{n}{i}] i=1ni[in]大力数论分块,这样总复杂度还是 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <unordered_map>

using namespace std;

using ll = long long;

int const M = 1000000;
int const N = M + 5;
int const mod = 1e9 + 7;

ll KSM(ll a, ll k) {
	ll ret = 1;
	for (; k; k >>= 1, a = a * a % mod) 
		if (k & 1)
			ret = ret * a % mod;
	return ret;
}

int f[N], c[N], su[N], low[N];
ll g[N];
int pri[N], tot;
bool isp[N];
ll inv2, inv3;

void SAI() {
	isp[1] = 1;
	low[1] = f[1] = su[1] = 1;
	g[1] = 1;
	for (int i = 2; i <= M; ++i) {
		if (isp[i] == 0) {
			pri[++tot] = i;
			f[i] = -1;
			g[i] = su[i] = i + 1;
			low[i] = i;
		}
		for (int j = 1; j <= tot && i * pri[j] <= M; ++j) {
			isp[i * pri[j]] = 1;
			if (i % pri[j]) {
				f[i * pri[j]] = -f[i];
				low[i * pri[j]] = pri[j];
				su[i * pri[j]] = pri[j] + 1;
				g[i * pri[j]] = g[i] * g[pri[j]];
			} else {
				f[i * pri[j]] = 0;
				low[i * pri[j]] = low[i] * pri[j];
				su[i * pri[j]] = su[i] + low[i * pri[j]];
				g[i * pri[j]] = g[i] / su[i] * su[i * pri[j]];
				break;
			}
		}
	}
	for (int i = 1; i <= M; ++i) {
		f[i] = (1ll * i * f[i] % mod + f[i - 1]) % mod;
		g[i] = (g[i] + g[i - 1]) % mod;
	}
}

unordered_map<int, int> mp;

int sum_(int x) {
	if (x <= M)
		return f[x];
	if (mp.count(x) > 0)
		return mp[x];
	int ret = 1;
	for (int l = 2, r; l <= x; l = r + 1) {
		r = x / (x / l);
		ret = (ret - 1ll * (r - l + 1) * (l + r) % mod * inv2 % mod * sum_(x / l) % mod) % mod;
	}
	ret = (ret + mod) % mod;
	mp[x] = ret;
	return ret;
}

int sig_(int x) {
	if (x <= M)
		return g[x] % mod;
	int ret = 0;
	for (int l = 1, r; l <= x; l = r + 1) {
		r = x / (x / l);
		ret += 1ll * (x / l) * (l + r) % mod * (r - l + 1) % mod * inv2 % mod;
		if (ret >= mod)
			ret -= mod;
	}
	return ret;
}

int main() {
	SAI();
	int T = 1;
	inv2 = KSM(2, mod - 2);
	inv3 = KSM(3, mod - 2);
	while (T--) {
		int n;
		scanf("%d", &n);
		int ans = 0;
		for (int l = 1, r; l <= n; l = r + 1) {
			r = n / (n / l);
			int nd = n / l, t = sig_(nd);
			ans = (ans + 1ll * t * t % mod * (sum_(r) - sum_(l - 1))) % mod;
		}
		ans = (ans + mod) % mod;
		printf("%d\n", ans);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值