线性筛与积性函数

线性筛与积性函数

定义:积性函数指对于所有互质的整数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 1xn区间内,使得 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 dn1)
- σ ( n ) \sigma(n) σ(n) 约数和函数 ( ∑ d ∣ n d \sum_{d|n}d dnd)

辅助、基本积性函数:

- ε ( 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)=dnf(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) dnμ(d)I(dn)=dnμ(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 dn都有 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(tk,vtak)
根据定义得当 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 dnμ(d)=i=0nC(k,i)=0
所以 s u m d ∣ n μ ( d ) = [ n = 1 ] sum_{d \mid n}\mu(d)=[n=1] sumdnμ(d)=[n=1]
2. 若 F ( n ) = ∑ d ∣ n f ( d ) F(n)=\sum_{d \mid n}f(d) F(n)=dnf(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)=dnμ(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)=dnμ(d)ednf(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)=dnednμ(d)f(e)
因为稍微理解一下,发现其实是所有满足 ( d ⋅ e ) ∣ n (d⋅e)|n (de)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)=endenμ(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)=enf(e)denμ(d)
所以 f ( n ) = ∑ e ∣ n f ( e ) ∗ [ n e = 1 ] f(n)=\sum_{e|n}f(e)*[\frac{n}{e}=1] f(n)=enf(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)=dnμ(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(pi),都有 μ ( i ∗ p j ) = μ ( i ) ∗ μ ( p j ) \mu(i*p_j)=\mu(i)*\mu(p_j) μ(ipj)=μ(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 μ(ipj)=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)=pkpk1
证明: 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} pkpk1
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 bn,gcd(a,b)=1,那么以 b b b为分母的数就有 φ ( a ) \varphi(a) φ(a)个,又因为 b ∣ n b \mid n bn,所以 ∑ d ∣ n φ ( d ) = n ( 总 共 有 n 个 分 数 ) \sum_{d|n}\varphi(d)=n(总共有n个分数) dnφ(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)=φ(pk1)p
证明: ∵ φ ( p k ) = p k − 1 ∗ ( p − 1 ) \because \varphi(p^k)=p^{k-1}*(p-1) φ(pk)=pk1(p1)
∵ φ ( p k − 1 ) = p k − 2 ∗ ( p − 1 ) \because \varphi(p^{k-1})=p^{k-2}*(p-1) φ(pk1)=pk2(p1)
∴ p k − 1 = φ ( p k − 1 ) ∗ p / ( p − 1 ) \therefore p^{k-1}=\varphi(p^{k-1})*p/(p-1) pk1=φ(pk1)p/(p1)
∴ φ ( p k ) = φ ( p k − 1 ) ∗ p \therefore \varphi(p^k)=\varphi(p^{k-1})*p φ(pk)=φ(pk1)p

线性筛欧拉函数:

做法:在线性筛的基础上加上,若 i i i为质数,则 φ ( i ) = i − 1 \varphi(i)=i-1 φ(i)=i1,之后根据他是积性函数的定义,则对于的 i m o d    p j ≠ 0 ( p 为 小 于 i 的 质 数 集 和 ) i \mod p_j\not=0(p为小于i的质数集和) imodpj=0(pi),都有 φ ( i ∗ p j ) = φ ( i ) ∗ φ ( p j ) \varphi(i*p_j)=\varphi(i)*\varphi(p_j) φ(ipj)=φ(i)φ(pj),若是 i m o d    p j = 0 i \mod p_j=0 imodpj=0,则我们将 i ∗ p j i*p_j ipj写成互质的形式, i ∗ p j = t ∗ p j w i*p_j=t*p_j^w ipj=tpjw,所以 φ ( 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= φ(ipj)=φ(tpjw)=φ(t)φ(pjw1)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α1p2α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)=dn(1)rdn,所以: φ ( n ) = ∑ d ∣ n μ ( d ) i d ( n d ) \varphi(n)=\sum_{d|n}\mu(d)id(\frac{n}{d}) φ(n)=dnμ(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=fg
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=1ndif(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=1dnf(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=1dnf(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)=1i=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=1nii=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:信息学 数论 线性筛 积性函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值