杜教筛_分级筛和振动筛「建议收藏」

杜教筛_分级筛和振动筛「建议收藏」杜教筛首先我们要知道杜教筛是用来求积性函数的前缀和的

杜教筛_分级筛和振动筛「建议收藏」"

杜教筛

首先我们要知道杜教筛是用来求积性函数的前缀和的。

前置知识1:积性函数

a a a b b b互质,那么有 f ( a b ) = f ( a ) f ( b ) f(ab) = f(a)f(b) f(ab)=f(a)f(b),则称 f ( x ) f(x) f(x)为积性函数。
若函数 f ( x ) f(x) f(x),对于任意两个数 a a a b b b,都有 f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b),则称 f ( x ) f(x) f(x)为完全积性函数

常见的积性函数

  • 欧拉函数 φ ( x ) \varphi (x) φ(x) x x x小的与 x x x互质的数的个数
  • 莫比乌斯函数 μ ( x ) = { 1 , x = 1 ( − 1 ) k , x = p 1 p 2 ⋯ p k , p i 为 不 相 等 的 素 数 0 , x 有 大 于 1 的 平 方 数 因 数 \mu (x) =\left\{\begin{matrix} 1, x = 1\\ (-1)^k,x=p_1p_2\cdots p_k,p_i为不相等的素数\\ 0,x有大于1的平方数因数 \end{matrix}\right. μ(x)=1,x=1(1)k,x=p1p2pk,pi0,x1
  • 正因子和 σ ( x ) = ∑ d ∣ x d \sigma (x) = \sum_{d|x}d σ(x)=dxd
  • 正因子个数 σ ( x ) = ∑ d ∣ x 1 \sigma (x) = \sum_{d|x}1 σ(x)=dx1

常见的完全积性函数

  • ϵ ( x ) = [ x = = 1 ] \epsilon (x) = [x == 1] ϵ(x)=[x==1]
  • I ( x ) = 1 I(x) = 1 I(x)=1
  • i d ( x ) = x id(x) = x id(x)=x

前置知识2:狄利克雷卷积

定义: 对于两个积性函数 f ( n ) g ( n ) f(n) g(n) f(n)g(n)的狄利克雷卷积为 ( f ∗ g ) ( i ) = ∑ d ∣ n f ( d ) ∗ g ( n d ) (f*g)(i) = \sum_{d|n}f(d)*g(\frac{n}{d}) (fg)(i)=dnf(d)g(dn),也就是对于 i ∗ j = = n i * j == n ij==n的整数 i , j i,j i,j的函数值乘在一起再求和。

狄利克雷卷积满足结合律和交换律
单位函数 ϵ ( x ) \epsilon (x) ϵ(x)是狄利克雷卷积的单位元,任何函数卷上 ϵ ( x ) \epsilon (x) ϵ(x)都是它本身

一些狄利克雷卷积的结论:
1. μ ∗ I = ϵ ( x ) \mu * I = \epsilon(x) μI=ϵ(x)
2. φ ∗ I = i d ( x ) \varphi * I = id(x) φI=id(x)
3. i d ∗ μ = φ ( x ) id * \mu = \varphi(x) idμ=φ(x)

前置知识3:莫比乌斯反演

对弈两个积性函数如果有 f = g ∗ I f = g * I f=gI, 则有 g = f ∗ μ g = f * \mu g=fμ
把卷积拆开,原式为 f ( x ) = ∑ d ∣ x g ( d ) f(x) = \sum_{d|x}g(d) f(x)=dxg(d),则有 g ( x ) = ∑ d ∣ x f ( x d ) ∗ μ ( d ) g(x) = \sum_{d|x}f(\frac{x}{d})*\mu(d) g(x)=dxf(dx)μ(d)
证明:
f = g ∗ I f = g * I f=gI
f ∗ μ = g ∗ I ∗ μ f * \mu = g * I * \mu fμ=gIμ
f ∗ μ = g ∗ ϵ f * \mu = g * \epsilon fμ=gϵ
f ∗ μ = g f * \mu = g fμ=g

杜教筛

我们构造积性函数 f , g f,g f,g,令 S ( n ) = ∑ i = 1 n f ( i ) S(n) = \sum_{i = 1}^n f(i) S(n)=i=1nf(i)
S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) ∗ S ( n i ) g ( 1 ) S(n) = \frac{\sum_{i = 1}^{n}(f*g)(i) – \sum_{i = 2}^{n}g(i)*S(\frac{n}{i})}{g(1)} S(n)=g(1)i=1n(fg)(i)i=2ng(i)S(in)
称此公式为杜教筛公式
证明略

这里放一道洛谷的模板题:传送门

题中的 a n s 1 = ∑ i = 1 n φ ( i ) ans_1 = \sum_{i = 1}^{n} \varphi (i) ans1=i=1nφ(i)
我们令 S ( n ) = ∑ i = 1 n φ ( i ) S(n) = \sum_{i = 1}^{n} \varphi (i) S(n)=i=1nφ(i)
我们令 g = I g = I g=I
代入杜教筛公式 S ( n ) = ∑ i = 1 n ϵ ( i ) − ∑ i = 2 n I ( i ) ∗ S ( n i ) 1 S(n) = \frac{\sum_{i = 1}^{n}\epsilon (i) – \sum_{i = 2}^{n} I(i) * S(\frac{n}{i}) }{1} S(n)=1i=1nϵ(i)i=2nI(i)S(in)
S ( n ) = 1 − ∑ i = 2 n ∗ S ( n i ) S(n) = 1 – \sum_{i = 2}^{n} * S(\frac{n}{i}) S(n)=1i=2nS(in)
然后就用数论分块模板求 S ( n ) S(n) S(n)了,但直接这样求显然是做不到线性的复杂度的,所以我们需要预处理出 μ ( i ) φ ( i ) \mu(i) \varphi(i) μ(i)φ(i),然后对于求过的答案用 m a p map map记录来降低时间复杂度。经过证明,当预处理的值为 n 2 3 n^{\frac{2}{3}} n32时,时间复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)

a n s 2 ans2 ans2也可以用同样的方法进行化简,最后的式子为
S ( n ) = n ( n + 1 ) 2 − ∑ i = 2 n ∗ S ( n i ) S(n) = \frac{n(n + 1)}{2} – \sum_{i = 2}^{n} * S(\frac{n}{i}) S(n)=2n(n+1)i=2nS(in)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define LL __int128;
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define fi first
#define se second
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define PAUSE system("pause");
const double eps = 1e-8;
const int maxn = 5e6 + 10;
const int mod = 1e9 + 7; 
int prime[maxn], mu[maxn], check[maxn];
ll phi[maxn];
unordered_map<ll, int> ans_mu;
unordered_map<ll, ll> ans_phi;
void init() { 
   
	mu[1] = 1;
	phi[1] = 1;
	int tot = 0;
	for(int i = 2; i <= maxn; i++) { 
   
		if(!check[i]) { 
   
			prime[tot++] = i;
			mu[i] = -1;
			phi[i] = i - 1;
		}
		for(int j = 0; j < tot; j++) { 
   
			if(i * prime[j] > maxn) break;
			check[i * prime[j]] = true;
			if(i % prime[j] == 0) { 
   
				mu[i * prime[j]] = 0;
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			else{ 
   
				phi[i * prime[j]] = phi[i] * (prime[j] - 1);
				mu[i * prime[j]] = -mu[i];
			}
		}
	}
	for(int i = 1; i <= maxn; i++) { 
   
		mu[i] += mu[i - 1];
		phi[i] += phi[i - 1];
	}
}
int get_mu(ll x) { 
   
	if(x <= maxn) return mu[x];
	if(ans_mu[x]) return ans_mu[x];
	int ans = 1;
	for(ll l = 2, r; l <= x; l = r + 1){ 
   
    	r = x / (x / l);
    	ans -= (r - l + 1) * get_mu(x / l);
	}
	ans_mu[x] = ans;
	return ans;
}
ll get_phi(ll x) { 
   
	if(x <= maxn) return phi[x];
	if(ans_phi[x]) return ans_phi[x];
	ll ans = (ll)(x + 1) * (ll)x / 2;
	for(ll l = 2, r; l <= x; l = r + 1){ 
   
    	r = x / (x / l);
    	ans -= (r - l + 1) * get_phi(x / l);
	}
	ans_phi[x] = ans;
	return ans;
}
void solve(){ 
   
	ll n;
	scanf("%lld", &n);
	printf("%lld %d\n", get_phi(n), get_mu(n));
}
int main() { 
   
	init();
	int t = 1;
	scanf("%d", &t);
	// cin>>t;
	while(t--)
		solve();
	PAUSE;
	return 0;
}

今天的文章杜教筛_分级筛和振动筛「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/66609.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注