杜教筛
首先我们要知道杜教筛是用来求积性函数的前缀和的。
前置知识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=p1p2⋯pk,pi为不相等的素数0,x有大于1的平方数因数
- 正因子和 σ ( x ) = ∑ d ∣ x d \sigma (x) = \sum_{d|x}d σ(x)=∑d∣xd
- 正因子个数 σ ( x ) = ∑ d ∣ x 1 \sigma (x) = \sum_{d|x}1 σ(x)=∑d∣x1
常见的完全积性函数
- ϵ ( 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}) (f∗g)(i)=∑d∣nf(d)∗g(dn),也就是对于 i ∗ j = = n i * j == n i∗j==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=g∗I, 则有 g = f ∗ μ g = f * \mu g=f∗μ
把卷积拆开,原式为 f ( x ) = ∑ d ∣ x g ( d ) f(x) = \sum_{d|x}g(d) f(x)=∑d∣xg(d),则有 g ( x ) = ∑ d ∣ x f ( x d ) ∗ μ ( d ) g(x) = \sum_{d|x}f(\frac{x}{d})*\mu(d) g(x)=∑d∣xf(dx)∗μ(d)
证明:
f = g ∗ I f = g * I f=g∗I
f ∗ μ = g ∗ I ∗ μ f * \mu = g * I * \mu f∗μ=g∗I∗μ
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(f∗g)(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=1∑nφ(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)=1∑i=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)=1−i=2∑n∗S(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=2∑n∗S(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