线性筛与积性函数
定义:积性函数指对于所有互质的整数a和b有性质 f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b)的数论函数( a , b a,b a,b在正整数域内,以下一切讨论都在正整数域内)。
常见的积性函数:
- φ ( n ) \varphi(n) φ(n) 欧拉函数(在 1 ≤ x ≤ n 1 \leq x \leq n 1≤x≤n区间内,使得 g c d ( x , n ) = 1 gcd(x,n)=1 gcd(x,n)=1成立的 x x x的个数)
- μ ( n ) \mu(n) μ(n) 莫比乌斯函数(定义:令 n = a 1 b 1 a 2 b 2 . . . a t b t n=a_{1}^{b_1}a_{2}^{b_2}...a_{t}^{b_t} n=a1b1a2b2...atbt,若 ∑ i = 1 n [ b i > = 2 ] > 0 \sum_{i=1}^{n}[b_{i}>=2]>0 ∑i=1n[bi>=2]>0,则 μ ( n ) = 0 \mu(n)=0 μ(n)=0,否则 μ ( n ) = ( − 1 ) t \mu(n)=(-1)^t μ(n)=(−1)t,特别的 μ ( 1 ) = 1 \mu(1)=1 μ(1)=1)
- d ( n ) d(n) d(n) 约数个数函数 ( ∑ d ∣ n 1 \sum_{d|n}1 ∑d∣n1)
- σ ( n ) \sigma(n) σ(n) 约数和函数 ( ∑ d ∣ n d \sum_{d|n}d ∑d∣nd)
辅助、基本积性函数:
- ε ( n ) = [ n = 1 ] \varepsilon(n)=[n=1] ε(n)=[n=1] (一元函数)
- i d ( n ) = n id(n)=n id(n)=n (单位函数)
- I ( n ) = 1 I(n)=1 I(n)=1 (恒等函数)
具体用法使用杜教筛时会用到
狄利克雷卷积:
定义:设 f ( n ) , g ( n ) f(n),g(n) f(n),g(n)是两个积性函数(数论函数),则它们的狄利克雷卷积 h ( n ) = ∑ d ∣ n f ( d ) g ( n d ) h(n)=\sum_{d|n}f(d)g(\frac{n}{d}) h(n)=∑d∣nf(d)g(dn),且它是积性函数(数论函数)
注:狄利克雷卷积的另一种表达方式 h ( n ) = ∑ a b = n f ( a ) g ( b ) h(n)=\sum_{ab=n}f(a)g(b) h(n)=∑ab=nf(a)g(b)
莫比乌斯函数:
性质证明:
1. μ ∗ I = ε \mu*I=\varepsilon μ∗I=ε
证明: ∑ d ∣ n μ ( d ) I ( n d ) = ∑ d ∣ n μ ( d ) \sum_{d \mid n}\mu(d)I(\frac{n}{d})=\sum_{d \mid n}\mu(d) ∑d∣nμ(d)I(dn)=∑d∣nμ(d)
因为当 n = 1 n=1 n=1时,上式 = 1 =1 =1,显然成立,所以我们只需要证明当 n > 1 n>1 n>1时,上式 = 0 =0 =0
我们不妨设 n = ∏ i = 1 k p k a k n=\prod_{i=1}^{k}p_k^{a_k} n=∏i=1kpkak,则对于任意的 d ∣ n d \mid n d∣n都有 d = ∏ i = 1 t p t v t ( t ≤ k , v t ≤ a k ) d=\prod_{i=1}^{t}p_t^{v_t} (t\leq k,v_t\leq a_k) d=∏i=1tptvt(t≤k,vt≤ak)
根据定义得当 v t > 1 v_t>1 vt>1时, μ ( d ) = 0 \mu(d)=0 μ(d)=0,所以当 v t = 1 v_t=1 vt=1时, μ ( d ) = ± 1 \mu(d)=\pm1 μ(d)=±1
其实就是相当于在 k k k个 − 1 -1 −1中,选择 t t t个,所以 ∑ d ∣ n μ ( d ) = ∑ i = 0 n C ( k , i ) = 0 \sum_{d \mid n}\mu(d)=\sum_{i=0}^{n}C(k,i)=0 ∑d∣nμ(d)=∑i=0nC(k,i)=0
所以 s u m d ∣ n μ ( d ) = [ n = 1 ] sum_{d \mid n}\mu(d)=[n=1] sumd∣nμ(d)=[n=1]
2. 若 F ( n ) = ∑ d ∣ n f ( d ) F(n)=\sum_{d \mid n}f(d) F(n)=∑d∣nf(d),则 f ( n ) = ∑ d ∣ n μ ( d ) F ( ⌊ n d ⌋ ) f(n)=\sum_{d \mid n}\mu(d)F(\lfloor \frac{n}{d} \rfloor) f(n)=∑d∣nμ(d)F(⌊dn⌋) [莫比乌斯反演]
证明: ∴ f ( n ) = ∑ d ∣ n μ ( d ) ∑ e ∣ n d f ( e ) \therefore f(n)=\sum_{d|n}\mu(d)\sum_{e|\frac{n}{d}}f(e) ∴f(n)=∑d∣nμ(d)∑e∣dnf(e)
由分配律我们可以知道 f ( n ) = ∑ d ∣ n ∑ e ∣ n d μ ( d ) f ( e ) f(n)=\sum_{d|n}\sum_{e|\frac{n}{d}}\mu(d)f(e) f(n)=∑d∣n∑e∣dnμ(d)f(e)
因为稍微理解一下,发现其实是所有满足 ( d ⋅ e ) ∣ n (d⋅e)|n (d⋅e)∣n的二元组 ( d , e ) (d,e) (d,e)之于是可以交换前两个 ∑ \sum ∑的位置即,所以 f ( n ) = ∑ e ∣ n ∑ d ∣ n e μ ( d ) f ( e ) f(n)=\sum_{e|n}\sum_{d|\frac{n}{e}}\mu(d)f(e) f(n)=∑e∣n∑d∣enμ(d)f(e)
再由分配律逆定理可知 f ( n ) = ∑ e ∣ n f ( e ) ∑ d ∣ n e μ ( d ) f(n)=\sum_{e|n}f(e)\sum_{d|\frac{n}{e}}\mu(d) f(n)=∑e∣nf(e)∑d∣enμ(d)
所以 f ( n ) = ∑ e ∣ n f ( e ) ∗ [ n e = 1 ] f(n)=\sum_{e|n}f(e)*[\frac{n}{e}=1] f(n)=∑e∣nf(e)∗[en=1],所以只有当 n = e n=e n=e时,取值才有效,所以 f ( n ) = f ( n ) = ∑ d ∣ n μ ( d ) F ( ⌊ n d ⌋ ) f(n)=f(n)=\sum_{d \mid n}\mu(d)F(\lfloor \frac{n}{d} \rfloor) f(n)=f(n)=∑d∣nμ(d)F(⌊dn⌋)
线性筛莫比乌斯函数:
做法:在线性筛的基础上加上,若 i i i为质数,则 μ ( i ) = − 1 \mu(i)=-1 μ(i)=−1,之后根据他是积性函数的定义,则对于的 i m o d p j ≠ 0 ( p 为 小 于 i 的 质 数 集 和 ) i \mod p_j \not =0(p为小于i的质数集和) imodpj=0(p为小于i的质数集和),都有 μ ( i ∗ p j ) = μ ( i ) ∗ μ ( p j ) \mu(i*p_j)=\mu(i)*\mu(p_j) μ(i∗pj)=μ(i)∗μ(pj),若是 i m o d p j = 0 i \mod p_j=0 imodpj=0,则有至少一个二次以上的指数,所以 μ ( i ∗ p j ) = 0 \mu(i*p_j)=0 μ(i∗pj)=0.
代码实现:
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 20000000
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int mu[maxn+5];
int p[maxn+5],bz[maxn+5],len;
void find_prime()
{
mu[1]=1;
for (int i=2;i<=maxn;i++)
{
if (bz[i]==false) mu[i]=-1,len++,p[len]=i;
for (int j=1;j<=len && i*p[j]<=maxn;j++)
{
bz[i*p[j]]=1;
if (i%p[j]==0) { mu[i*p[j]]=0; break; }
else mu[i*p[j]]=mu[i]*mu[p[j]];
}
}
}
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
find_prime();
// fclose(stdin);fclose(stdout);
return 0;
}
欧拉函数:
性质证明:
1. 若 p p p为质数,则 φ ( p k ) = p k − p k − 1 \varphi(p^k)=p^k-p^{k-1} φ(pk)=pk−pk−1
证明: 1 1 1~ p k p^k pk总共有 p k p^k pk个数,因为 p p p是质数,所以其中与 p p p不互质的只有 p p p的倍数,而 p k p^k pk中有 p k / k p^k/k pk/k个倍数,所以互质数就为 p k − p k − 1 p^k-p^{k-1} pk−pk−1
2. φ ∗ I = i d \varphi*I=id φ∗I=id
证明:给出 1 n , 2 n , 3 n . . . , n n n \frac{1}{n},\frac{2}{n},\frac{3}{n}...,\frac{n}{n} n n1,n2,n3...,nnn个分数,把他们化为最简形式 a b \frac{a}{b} ba,那什么 a , b a,b a,b要有什么条件呢?经过观察发现, b ∣ n , g c d ( a , b ) = 1 b \mid n , gcd(a,b)=1 b∣n,gcd(a,b)=1,那么以 b b b为分母的数就有 φ ( a ) \varphi(a) φ(a)个,又因为 b ∣ n b \mid n b∣n,所以 ∑ d ∣ n φ ( d ) = n ( 总 共 有 n 个 分 数 ) \sum_{d|n}\varphi(d)=n(总共有n个分数) ∑d∣nφ(d)=n(总共有n个分数),所以 φ ∗ I = i d \varphi*I=id φ∗I=id
3. φ ( p k ) = φ ( p k − 1 ) ∗ p \varphi(p^k)=\varphi(p^{k-1})*p φ(pk)=φ(pk−1)∗p
证明: ∵ φ ( p k ) = p k − 1 ∗ ( p − 1 ) \because \varphi(p^k)=p^{k-1}*(p-1) ∵φ(pk)=pk−1∗(p−1)
又 ∵ φ ( p k − 1 ) = p k − 2 ∗ ( p − 1 ) \because \varphi(p^{k-1})=p^{k-2}*(p-1) ∵φ(pk−1)=pk−2∗(p−1)
∴ p k − 1 = φ ( p k − 1 ) ∗ p / ( p − 1 ) \therefore p^{k-1}=\varphi(p^{k-1})*p/(p-1) ∴pk−1=φ(pk−1)∗p/(p−1)
∴ φ ( p k ) = φ ( p k − 1 ) ∗ p \therefore \varphi(p^k)=\varphi(p^{k-1})*p ∴φ(pk)=φ(pk−1)∗p
线性筛欧拉函数:
做法:在线性筛的基础上加上,若 i i i为质数,则 φ ( i ) = i − 1 \varphi(i)=i-1 φ(i)=i−1,之后根据他是积性函数的定义,则对于的 i m o d p j ≠ 0 ( p 为 小 于 i 的 质 数 集 和 ) i \mod p_j\not=0(p为小于i的质数集和) imodpj=0(p为小于i的质数集和),都有 φ ( i ∗ p j ) = φ ( i ) ∗ φ ( p j ) \varphi(i*p_j)=\varphi(i)*\varphi(p_j) φ(i∗pj)=φ(i)∗φ(pj),若是 i m o d p j = 0 i \mod p_j=0 imodpj=0,则我们将 i ∗ p j i*p_j i∗pj写成互质的形式, i ∗ p j = t ∗ p j w i*p_j=t*p_j^w i∗pj=t∗pjw,所以 φ ( i ∗ p j ) = φ ( t ∗ p j w ) = φ ( t ) ∗ φ ( p j w − 1 ) ∗ p j = \varphi(i*p_j)=\varphi(t*p_j^w)=\varphi(t)*\varphi(p_j^{w-1})*p_j= φ(i∗pj)=φ(t∗pjw)=φ(t)∗φ(pjw−1)∗pj= φ ( i ) ∗ p j \varphi(i)*p_j φ(i)∗pj,所以做完。
代码实现:
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 20000000
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int t,n;
int ol[maxn+5];
int p[maxn+5],bz[maxn+5],len;
void find_prime()
{
ol[1]=1;
for (int i=2;i<=maxn;i++)
{
if (bz[i]==false) ol[i]=i-1,len++,p[len]=i;
for (int j=1;j<=len && i*p[j]<=maxn;j++)
{
bz[i*p[j]]=1;
if (i%p[j]==0) { ol[i*p[j]]=ol[i]*p[j]; break; }
else ol[i*p[j]]=ol[i]*ol[p[j]];
}
}
}
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
find_prime();
// fclose(stdin);fclose(stdout);
return 0;
}
莫比乌斯函数与欧拉函数加回来。同时你又发现,把 d d d质因数分解, d = p 1 α 1 ∗ p 2 α 2 ∗ . . . ∗ p r α r d=p_1^{\alpha_1}*p_2^{\alpha_2}*...*p_r^{\alpha_r} d=p1α1∗p2α2∗...∗prαr。若 α i \alpha_i αi,则用 d d d减去的数肯定就会被它的因数减过,并被刚好减一次(自己仔细想想)。所以我们也可以忽略这种情况,不加也不减。所以你可以发现:这其实就是一个容斥原理: φ ( n ) = ∑ d ∣ n ( − 1 ) r ∗ n d \varphi(n)=\sum_{d|n}(-1)^r*\frac{n}{d} φ(n)=∑d∣n(−1)r∗dn,所以: φ ( n ) = ∑ d ∣ n μ ( d ) i d ( n d ) \varphi(n)=\sum_{d|n}\mu(d)id(\frac{n}{d}) φ(n)=∑d∣nμ(d)id(dn)
杜教筛基本套路
作用:用来求积性函数 f ( n ) f(n) f(n)的前缀和 F ( n ) = ∑ i = 1 n f ( n ) F(n)=\sum_{i=1}^{n}f(n) F(n)=∑i=1nf(n)
过程:
1. 当看到这种题的时候,D老师想到了用狄利克雷卷积来解决,所以他g构造两个积性函数 h , g h,g h,g,使得 h = f ∗ g h=f*g h=f∗g
2. ∵ ∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i f ( d ) g ( i d ) \ \because \sum_{i=1}^{n}h(i)=\sum_{i=1}^{n}\sum_{d|i}f(d)g(\frac{i}{d}) ∵∑i=1nh(i)=∑i=1n∑d∣if(d)g(di) (由狄利克雷卷积的定义可得)
3. ∴ ∑ i = 1 n h ( i ) = ∑ i = 1 n [ g ( d ) ∗ ∑ i = 1 ⌊ n d ⌋ f ( i ) ] \ \therefore \sum_{i=1}^{n}h(i)=\sum_{i=1}^{n}[g(d)*\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}f(i)] ∴∑i=1nh(i)=∑i=1n[g(d)∗∑i=1⌊dn⌋f(i)] (把上式拆解开来,我们可以得到 f ( d 1 , 1 ) ∗ g ( i 1 d 1 , 1 ) + f ( d 1 , 2 ) ∗ g ( i 1 d 1 , 2 ) + . . . + f ( d 1 , t i ) ∗ g ( i 1 d 1 , t i ) + . . . + f(d_{1,1})*g(\frac{i_1}{d_{1,1}})+f(d_{1,2})*g(\frac{i_1}{d_{1,2}})+...+f(d_{1,t_i})*g(\frac{i_1}{d_{1,t_i}})+...+ f(d1,1)∗g(d1,1i1)+f(d1,2)∗g(d1,2i1)+...+f(d1,ti)∗g(d1,tii1)+...+ f ( d n , 1 ) ∗ g ( i n d n , 1 ) f(d_{n,1})*g(\frac{i_n}{d_{n,1}}) f(dn,1)∗g(dn,1in) + . . . + f ( d n , t n ) ∗ g ( i n d n , t n ) +...+f(d_{n,t_n})*g(\frac{i_n}{d_{n,t_n}}) +...+f(dn,tn)∗g(dn,tnin),之后我们就可以知道 ∑ d = 1 n g ( d ) \sum_{d=1}^{n} g(d) ∑d=1ng(d)都出现了,那么每个 g ( d ) g(d) g(d)出现了多少次呢?经过观察我们发现,对于每个 g ( d ) g(d) g(d)它在 1 1 1~ n n n范围内,只要是 d d d的倍数的数,就都会含有 g ( d ) g(d) g(d),所以每个 g ( d ) g(d) g(d)总共出现了 ∑ i = 1 ⌊ n d ⌋ f ( i ) \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}f(i) ∑i=1⌊dn⌋f(i)次)
4. ∴ ∑ i = 1 n h ( i ) = ∑ i = 1 n [ g ( d ) ∗ F ( ⌊ n d ⌋ ) ] \ \therefore \sum_{i=1}^{n}h(i)=\sum_{i=1}^{n}[g(d)*F(\lfloor \frac{n}{d} \rfloor)] ∴∑i=1nh(i)=∑i=1n[g(d)∗F(⌊dn⌋)] (根据 F ( n ) F(n) F(n)的定义,直接代入)
5. ∴ ∑ i = 1 n h ( i ) = g ( 1 ) F ( n ) + ∑ i = 2 n [ g ( d ) ∗ F ( ⌊ n d ⌋ ) ] \ \therefore \sum_{i=1}^{n}h(i)=g(1)F(n)+\sum_{i=2}^{n}[g(d)*F(\lfloor \frac{n}{d} \rfloor)] ∴∑i=1nh(i)=g(1)F(n)+∑i=2n[g(d)∗F(⌊dn⌋)] (将 i = 1 i=1 i=1提取出来,因为 d = 1 d=1 d=1,所以 ⌊ n d ⌋ = n \lfloor \frac{n}{d} \rfloor=n ⌊dn⌋=n)
6. ∴ g ( 1 ) F ( n ) = ∑ i = 1 n h ( i ) − ∑ i = 2 n [ g ( d ) ∗ F ( ⌊ n d ⌋ ) ] \therefore g(1)F(n)=\sum_{i=1}^{n}h(i)-\sum_{i=2}^{n}[g(d)*F(\lfloor \frac{n}{d} \rfloor)] ∴g(1)F(n)=∑i=1nh(i)−∑i=2n[g(d)∗F(⌊dn⌋)] (移项易得)
7. 找得一个 g ( n ) g(n) g(n)使得 ∑ i = 1 n h ( i ) \sum_{i=1}^{n}h(i) ∑i=1nh(i)能在短时间内求出,那么我们就可以分块求出 − ∑ i = 2 n [ g ( d ) ∗ F ( ⌊ n d ⌋ ) ] -\sum_{i=2}^{n}[g(d)*F(\lfloor \frac{n}{d} \rfloor)] −∑i=2n[g(d)∗F(⌊dn⌋)],总体时间复杂度在 n 3 4 n^{\frac{3}{4}} n43左右
题目:
莫比乌斯之和(题面)
解析:根据杜教筛套路式,我们容易得出 I ( n ) I(n) I(n)就是可以让我们快速求出的积性函数,那么 F ( n ) = ∑ i = 1 n g ( i ) ∗ f ( i ) − ∑ i = 2 n [ g ( d ) ∗ F ( ⌊ n d ⌋ ) ] F(n)=\sum_{i=1}^{n}g(i)*f(i)-\sum_{i=2}^{n}[g(d)*F(\lfloor \frac{n}{d} \rfloor)] F(n)=∑i=1ng(i)∗f(i)−∑i=2n[g(d)∗F(⌊dn⌋)],又因为 μ ∗ I = ε \mu*I=\varepsilon μ∗I=ε,所以 F ( n ) = 1 − ∑ i = 2 n [ I ( d ) ∗ F ( ⌊ n d ⌋ ) ] F(n)=1-\sum_{i=2}^{n}[I(d)*F(\lfloor \frac{n}{d} \rfloor)] F(n)=1−∑i=2n[I(d)∗F(⌊dn⌋)],之后分块求解即可。
代码实现:
#include<bits/stdc++.h>
#define MAXN 5000000
#define mod 2333333
#define ll long long
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
struct my_map{
ll x;int ans,next;
}e[MAXN+5];
int f[MAXN+5],ans=0,num=0,s[MAXN],head[mod+5];
bool b[MAXN+5];
void ins(ll x,int sum)
{
int j=x%mod;
e[++num]=(my_map){x,sum,head[j]};
head[j]=num;
}
int calc(ll n)
{
if(n<=MAXN) return f[n];
for(int i=head[n%mod];i;i=e[i].next)
if(e[i].x==n)return e[i].ans;
int sum=1,q=sqrt(n);
for(int i=2;i<=q;i++)
sum-=calc(n/i);
q=n/(q+1);
for(int i=1;i<=q;i++)
sum-=(n/i-(n/(i+1)))*calc(i);
ins(n,sum);
return sum;
}
int main()
{
f[1]=1;b[1]=1;
for(int i=2;i<=MAXN;i++)
{
if(!b[i]) s[++num]=i,f[i]=-1;
for(int j=1;j<=num&&s[j]*i<=MAXN;j++)
{
int t=s[j]*i; b[t]=1;
if(i%s[j]==0){f[t]=0;break;}
f[t]=-f[i];
}
}
for(int i=2;i<=MAXN;i++)
f[i]+=f[i-1];
num=0;
ll x=read();ans-=calc(x-1);
x=read();ans+=calc(x);
cout<<ans;
return 0;
}
###欧拉函数与莫比乌斯函数前缀和(题面)
####解析:关于莫比乌斯的跟上题一样,而欧拉函数有
φ
∗
I
=
i
d
\varphi*I=id
φ∗I=id,所以
g
=
I
g=I
g=I,所以
F
(
n
)
=
∑
i
=
1
n
i
−
∑
i
=
2
n
F
(
⌊
n
d
⌋
)
F(n)=\sum_{i=1}^{n}i-\sum_{i=2}^{n}F(\lfloor \frac{n}{d} \rfloor)
F(n)=∑i=1ni−∑i=2nF(⌊dn⌋),注意可以吧
⌊
n
d
⌋
\lfloor \frac{n}{d} \rfloor
⌊dn⌋相同的合并来算,减小时间,详见代码。
####代码实现:
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 20000000
#define int long long
using namespace std;
map<int,int> find_mu;
map<int,int> find_ol;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int t,n;
int ol[maxn+5],mu[maxn+5];
int p[maxn+5],bz[maxn+5],len;
void find_prime()
{
mu[1]=ol[1]=1;
for (int i=2;i<=maxn;i++)
{
if (bz[i]==false) mu[i]=-1,ol[i]=i-1,len++,p[len]=i;
for (int j=1;j<=len && i*p[j]<=maxn;j++)
{
bz[i*p[j]]=1;
if (i%p[j]==0) { mu[i*p[j]]=0,ol[i*p[j]]=ol[i]*p[j]; break; }
else mu[i*p[j]]=-mu[i],ol[i*p[j]]=ol[i]*ol[p[j]];
}
}
for (int i=1;i<=maxn-1;i++) mu[i+1]+=mu[i];
for (int i=1;i<=maxn-1;i++) ol[i+1]+=ol[i];
}
int dfs1(int x)
{
if (x<=maxn) return ol[x];
if (find_ol[x]!=0) return find_ol[x];
int sum=(1+x)*x/2;
for (int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
sum-=(r-l+1)*dfs1(x/l);
}
return find_ol[x]=sum;
}
int dfs2(int x)
{
if (x<=maxn) return mu[x];
if (find_mu[x]!=0) return find_mu[x];
int sum=1;
for (int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
sum-=(r-l+1)*dfs2(x/l);
}
return find_mu[x]=sum;
}
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
find_prime();
read(t);
while (t--)
{
read(n);
printf("%lld %lld\n",dfs1(n),dfs2(n));
}
// fclose(stdin);fclose(stdout);
return 0;
}
###欧拉函数前缀和(题面)
####解析:同上,用了乘法逆元
####代码实现:
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn = 5e6+5;
#define int long long
#define mod 1000000007
using namespace std;
typedef long long ll;
map<int,int> _ol;
int ol[maxn+5];
int p[maxn+5],len,bz[maxn+5];
int n;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
void find_prime()
{
ol[1]=1;
for (int i=2;i<=maxn;i++)
{
if (bz[i]==false) ol[i]=i-1,p[++len]=i;
for (int j=1;j<=len && i*p[j]<=maxn;j++)
{
bz[i*p[j]]=true;
if (i%p[j]==0) { ol[i*p[j]]=ol[i]*p[j]%mod; break; }
else ol[i*p[j]]=ol[i]*ol[p[j]]%mod;
}
}
for (int i=2;i<=maxn;i++)
ol[i]+=ol[i-1],ol[i]%=mod;
}
int find_ol(int x)
{
if (x<=maxn) return ol[x];
if (_ol[x]!=0) return _ol[x];
int sum=(1+x)*x%mod*500000004%mod;
while (sum<0) sum+=mod,sum%=mod;
for (int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
sum-=(r-l+1)*find_ol(x/l);
while (sum<0) sum+=mod,sum%=mod;
sum%=mod;
}
while (sum<0) sum+=mod,sum%=mod;
if (_ol[x]==0) _ol[x]=sum%mod;
return sum%mod;
}
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
find_prime();
read(n);
int t=find_ol(n);
while (t<0) t+=mod,t%=mod;
printf("%lld\n",t);
// fclose(stdin);fclose(stdout);
return 0;
}
Tags:信息学 数论 线性筛 积性函数