洛谷 P3768 :简单的数学题(莫比乌斯反演 + 杜教筛)

在这里插入图片描述


∑ i = 1 n ∑ j = 1 n i ∗ j ∗ g c d ( i , j ) \sum_{i = 1}^n\sum_{j = 1}^ni * j * gcd(i,j) i=1nj=1nijgcd(i,j) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i ∗ j ∗ d 3 ∗ [ g c d ( i , j ) = 1 ] =\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{d}\rfloor} i * j * d^3 * [gcd(i,j) = 1] =d=1ni=1dnj=1dnijd3[gcd(i,j)=1] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i ∗ j ∗ d 3 ∗ ∑ p ∣ g c d ( i , j ) μ ( p ) =\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{d}\rfloor} i * j * d^3 * \sum_{p | gcd(i,j)}\mu(p) =d=1ni=1dnj=1dnijd3pgcd(i,j)μ(p) = ∑ d = 1 n ∑ p = 1 ⌊ n d ⌋ μ ( p ) ∑ i = 1 ⌊ n d ∗ p ⌋ ∑ j = 1 ⌊ n d ∗ p ⌋ i ∗ j ∗ d 3 ∗ p 2 =\sum_{d = 1}^{n}\sum_{p =1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)\sum_{i = 1}^{\lfloor\frac{n}{d * p}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{d * p}\rfloor} i * j * d^3*p^2 =d=1np=1dnμ(p)i=1dpnj=1dpnijd3p2 = ∑ T = 1 n ∑ d ∣ T μ ( T d ) ∗ d 3 ∗ ( T d ) 2 ∗ f ( ⌊ n T ⌋ ) 2 , f ( n ) = ∑ i = 1 n i =\sum_{T = 1}^{n}\sum_{d | T}\mu(\frac{T}{d})*d^3*(\frac{T}{d})^2*f({\lfloor\frac{n}{T}\rfloor})^2,f(n) = \sum_{i = 1}^ni =T=1ndTμ(dT)d3(dT)2f(Tn)2,f(n)=i=1ni = ∑ T = 1 n T 2 ∑ d ∣ T μ ( T d ) ∗ d ∗ f ( ⌊ n T ⌋ ) 2 =\sum_{T = 1}^{n}T^2\sum_{d | T}\mu(\frac{T}{d})*d*f({\lfloor\frac{n}{T}\rfloor})^2 =T=1nT2dTμ(dT)df(Tn)2 = ∑ T = 1 n T 2 ϕ ( T ) ∗ f ( ⌊ n T ⌋ ) 2 =\sum_{T = 1}^{n}T^2\phi(T)*f({\lfloor\frac{n}{T}\rfloor})^2 =T=1nT2ϕ(T)f(Tn)2
f ( T ) = T 2 ∗ ϕ ( T ) f(T) = T ^2 * \phi(T) f(T)=T2ϕ(T)
n &lt; = 1 0 7 n &lt;= 10^7 n<=107的话可以用线性筛预处理 f f f函数前缀和,然后分块。
n 出到了 1 0 11 10^{11} 1011可以用杜教筛筛出 f f f函数的前缀和,然后分块

杜教筛的大致过程:选一个 积性函数 g g g,构造 h = g ∗ f h = g * f h=gf ∗ * 代表狄利克雷卷积),可知 h 也是一个积性函数。 h ( x ) = ∑ d ∣ x g ( d ) ∗ f ( x d ) h(x) = \sum_{d | x} g(d) * f(\frac{x}{d}) h(x)=dxg(d)f(dx) ∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) ∗ f ( i d ) \sum_{i = 1}^nh(i) = \sum_{i = 1}^n\sum_{d | i} g(d) * f(\frac{i}{d}) i=1nh(i)=i=1ndig(d)f(di) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ g ( d ) ∗ f ( i ) =\sum_{d = 1}^n\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor} g(d) * f(i) =d=1ni=1dng(d)f(i) 令 S ( n ) = ∑ i = 1 n f ( i ) : ∑ i = 1 n h ( i ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ g ( d ) ∗ f ( i ) = ∑ d = 1 n g ( d ) ∗ S ( ⌊ n d ⌋ ) = g ( 1 ) ∗ S ( n ) + ∑ d = 2 n g ( d ) ∗ S ( ⌊ n d ⌋ ) 令S(n) = \sum_{i = 1}^nf(i):\sum_{i = 1}^nh(i) =\sum_{d = 1}^n\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor} g(d) * f(i) =\sum_{d = 1}^ng(d)*S({\lfloor\frac{n}{d}\rfloor}) = g(1) * S(n) + \sum_{d = 2}^ng(d)*S({\lfloor\frac{n}{d}\rfloor}) S(n)=i=1nf(i)i=1nh(i)=d=1ni=1dng(d)f(i)=d=1ng(d)S(dn)=g(1)S(n)+d=2ng(d)S(dn) 移 项 : g ( 1 ) ∗ S ( n ) = ∑ i = 1 n h ( i ) − ∑ d = 2 n g ( d ) ∗ S ( ⌊ n d ⌋ ) 移项:g(1) * S(n) = \sum_{i = 1}^nh(i) - \sum_{d = 2}^ng(d)*S({\lfloor\frac{n}{d}\rfloor}) g(1)S(n)=i=1nh(i)d=2ng(d)S(dn) h ( i ) h(i) h(i)的前缀和可以在O(1)时间求得,则 S ( n ) S(n) S(n)可以通过分块加记忆化搜索来求,因此要选一个积性函数 f f f使得 h = g ∗ f h = g * f h=gf h h h 的前缀和容易求。
观 察 g ∗ f : ∑ d ∣ x g ( d ) ∗ f ( x d ) = ∑ d ∣ x g ( d ) ∗ ( x d ) 2 ∗ ϕ ( x d ) 观察g * f:\sum_{d | x}g(d) * f(\frac{x}{d}) = \sum_{d | x}g(d) * ({\frac{x}{d}})^2*\phi(\frac{x}{d}) gfdxg(d)f(dx)=dxg(d)(dx)2ϕ(dx)
g ( i ) g(i) g(i) i 2 i^2 i2时(方便去掉分母里的 d 2 d^2 d2) g ∗ f = ∑ d ∣ x d 2 ∗ ϕ ( x d ) = x 3 , 前 缀 和 公 式 为 : x 2 ∗ ( x + 1 ) 2 4 g * f = \sum_{d | x}d ^ 2 * \phi(\frac{x}{d}) =x ^ 3,前缀和公式为:\frac{x^2*(x + 1)^2}{4} gf=dxd2ϕ(dx)=x3:4x2(x+1)2
∑ i = 1 n i 2 = i ∗ ( i + 1 ) ∗ ( 2 ∗ i + 1 ) 6 \sum_{i = 1}^n i ^2 = \frac{i * (i + 1) * (2*i + 1)}{6} i=1ni2=6i(i+1)(2i+1)
于是就可以杜教筛了,注意记忆化,先用线性筛预处理 n \sqrt n n 的前缀和,记忆化可以用map 也可以 unordered_map 或自己的hash,由于洛谷unordered_map编译不通过,这里还是用map


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 6e6;
map<ll,ll> mp;
bool ispri[maxn + 100];
int pri[maxn + 100],phi[maxn + 100],mu[maxn + 100];
ll sum[maxn + 100];
ll n,mod;
ll inv2,inv4,inv6;
ll fpow(ll a,ll b) {
	ll r = 1;
	while(b) {
		if(b & 1) r = r * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return r;
}
void sieve(int n) {
	ispri[0] = ispri[1] = false;
	pri[0] = 0;mu[1] = 1;phi[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!ispri[i]) pri[++pri[0]] = i,mu[i] = -1,phi[i] = i - 1;
		for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
			ispri[i * pri[j]] = true;
			if(i % pri[j] == 0) {
				phi[i * pri[j]] = phi[i] * pri[j];
				break;
			}
			phi[i * pri[j]] = phi[i] * (pri[j] - 1);
			mu[i * pri[j]] = -mu[i];
		}
	}
	sum[0] = 0;
	for(int i = 1; i <= n; i++)
		sum[i] = (sum[i - 1] + phi[i] * (1ll * i * i % mod) % mod) % mod;
}
ll cal0(ll x) {
	x %= mod;
	return x * (x + 1) % mod * inv2 % mod;
}
ll cal1(ll x) {
	x %= mod;
	return x * x % mod * (x + 1) % mod * (x + 1) % mod * inv4 % mod;
}
ll cal2(ll x) {
	x %= mod;
	return x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}
ll getsum(ll p) {
	if(p <= maxn) return sum[p];
	if(mp[p]) return mp[p];
	ll l,r;
	ll res = cal1(p);
	for(l = 2; l <= p; l = r + 1) {
		r = (p / (p / l));
		ll t = getsum(p / l);
		res = (res + mod - t * ((cal2(r) - cal2(l - 1) + mod) % mod) % mod) % mod;
	}
	return mp[p] = (res + mod) % mod;
}
int main() {
	scanf("%lld%lld",&mod,&n);
	sieve(6000000);
	inv2 = fpow(2,mod - 2);
	inv4 = fpow(4,mod - 2);
	inv6 = fpow(6,mod - 2);
	ll l,r;
	ll ans = 0;
	for(l = 1; l <= n; l = r + 1) {
		r = (n / (n / l));
		ll t = (getsum(r) - getsum(l - 1) + mod) % mod;
		ll x = cal1(n / l);
		ans = (ans + x * t % mod) % mod;
	}
	printf("%lld\n",(ans + mod) % mod);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值