数论学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhouyuheng2003/article/details/84798775

前言

近来发现自己的数论知识需要进行补充,感觉自己相对别人落下了好多,所以打算写一篇博客(on 2018/12/4),跟进一下自己的知识储备

正文

1.数论函数

数论函数,指定义域为正整数、陪域为复数的函数
f : Z + C f:\mathbb{Z^+}\rightarrow\mathbb{C}

  • Tip:常数函数也是数论函数
    我们通常用一个数字代表常数函数,比如 1 1 代表 f ( n ) = 1 f(n)=1 , x x 代表 f ( n ) = x f(n)=x
2.加性函数

对于一个函数 f f ,如果对于 g c d ( a , b ) = 1 gcd(a,b)=1 满足 f ( a b ) = f ( a ) + f ( b ) f(ab)=f(a)+f(b) ,就称其为加性函数

3.常见加性函数
  • 质因子数
    ω ( n ) = p n 1 \omega(n)=\sum_{p|n}1
    p p 为质数
    g c d ( a , b ) = 1 gcd(a,b)=1 说明 a , b a,b 没有相同的质因子,所以这是加性函数
  • 质因子之和
    a 1 ( n ) = p n p a_1(n)=\sum_{p|n}p
    p p 为质数
    证明同“相异质因子数”的证明
4.完全加性函数

对于一个函数 f f ,如果 a , b \forall a,b 满足 f ( a b ) = f ( a ) + f ( b ) f(ab)=f(a)+f(b) ,就称其为完全加性函数

5.常见完全加性函数
  • 可相同质因子数
    Ω ( n ) = p n t \Omega(n)=\sum_{p|n}t
    p p 为质数, t t 为最大的整数满足 p t n p^t|n
    两数相乘,质因子数量可以直接合并
  • 可相同质因子之和
    a 0 ( n ) = p n p t a_0(n)=\sum_{p|n}p*t
    p p 为质数, t t 为最大的整数满足 p t n p^t|n
    证明同“可相同质因子数”的证明
6.积性函数

对于一个函数 f f ,如果 f ( 1 ) = 1 f(1)=1 ,且对于 g c d ( a , b ) = 1 gcd(a,b)=1 满足 f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)*f(b) ,就称其为积性函数

  • Tip:注意一定要满足 f ( 1 ) = 1 f(1)=1 ,这个条件把函数 f ( x ) = 0 f(x)=0 这个函数排除了
    证明:
    f ( a ) = f ( a ) f ( 1 ) \because f(a)=f(a)*f(1)
    f ( a ) ( f ( 1 ) 1 ) = 0 \therefore f(a)*(f(1)-1)=0
    f ( 1 ) = 1 f ( a ) = 0 \therefore f(1)=1或f(a)=0
7.常见积性函数
  • Euler’s totient function(欧拉函数)
    φ ( n ) \varphi(n) 表示 [ 1 , n ] [1,n] 中与 n n 互质的数个数
    φ ( n ) = n i = 1 k ( 1 1 p i ) \varphi(n)=n*\prod_{i=1}^{k}\left(1-\frac{1}{p_i}\right)
    其中 p 1 , p 2 p k p_1, p_2……p_k n n 的所有质因数
    容易发现每个质因数 p p φ ( n ) \varphi(n) 的贡献都是独立的,设 t t 为最大的整数满足 p t n p^t|n ,其贡献的乘积为: ( p 1 ) p t 1 (p-1)*p^{t-1}
    所以 φ ( n ) \varphi(n) 是积性函数
  • Möbius function(莫比乌斯函数)
    μ ( n ) = { 1 ,          n = 1 ( 1 ) k , n n = p 1 p 2 p k 0 ,          n \mu(n)=\begin{cases} 1,\ \ \ \ \ \ \ \ 若n=1 \\ (-1)^k,若n无平方数因数且n=p_1*p_2···p_k\\ 0,\ \ \ \ \ \ \ \ 若n有平方数因数 \end{cases}
    这是一个比较清楚的定义,容易发现每个质因数 p p μ ( n ) \mu(n) 的贡献都是独立的,设 t t 为最大的整数满足 p t n p^t|n ,其贡献的乘积为: { 1 , t = 1 0 ,     t > 1 \begin{cases}-1,若t=1\\ 0,\ \ \ 若t>1 \end{cases}
    所以 μ ( n ) \mu(n) 是积性函数
  • divisor function(除数函数)
    σ x ( n ) = d n d x \sigma_x(n)=\sum_{d|n}d^x
    这个积性函数的证明也非常简单,每加入一个质因数 p p σ x ( n ) \sigma_x(n) 的贡献都是使值乘上一个定值,设 t t 为最大的整数满足 p t n p^t|n ,其贡献的乘积为 i = 0 t p x i \sum_{i=0}^tp^{xi}
    所以除数函数还有一个式子是
    σ x ( n ) = p p j n p x j \sigma_x(n)=\prod_{p}\sum_{p^j|n}p^{xj}
    p p 为质数
    特殊的 σ x ( n ) \sigma_x(n) 有两个值得注意的情况
    σ 0 ( n ) \sigma_0(n) 代表 n n 的因数数量,也写作 d ( n ) d(n)
    σ 1 ( n ) \sigma_1(n) 代表 n n 的因数之和,也写作 σ ( n ) \sigma(n)
8.完全积性函数

对于一个函数 f f ,如果 f ( 1 ) = 1 f(1)=1 a , b \forall a,b 满足 f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)*f(b) ,就称其为完全积性函数

9.常见完全积性函数
  • power function(幂函数)
    I d k ( n ) = n k Id_k(n)=n^k
    证明很容易 I d k ( a ) I d k ( b ) = a k b k = ( a b ) k = I d k ( a b ) Id_k(a)*Id_k(b)=a^k*b^k=(a*b)^k=Id_k(a*b)
    特殊的 I d k ( n ) Id_k(n) 有两个值得注意的情况
    I d 0 ( n ) = 1 Id_0(n)=1 ,也写作 1 ( n ) 1(n) 或者是 I ( n ) I(n)
    I d 1 ( n ) = n Id_1(n)=n ,也写作 I d ( n ) Id(n)
  • Liouville function(刘维尔函数)
    λ ( n ) = ( 1 ) Ω ( n ) \lambda(n)=(-1)^{\Omega(n)}
    Ω ( n ) \Omega(n) 是完全加性函数,所以 λ ( n ) \lambda(n) 是完全积性函数
  • 单位函数
    ϵ ( n ) = { 1 , n = 1 0 , n > 1 \epsilon(n)=\begin{cases}1,n=1\\0,n>1 \end{cases}
    特殊的, ϵ ( n ) \epsilon(n) 有时也写作 e ( n ) e(n)
    显然是完全积性函数
Dirichlet product(狄利克雷卷积)

两个数论函数 f , g f,g ,他们的狄利克雷卷积为
( f g ) ( n ) = d n f ( d ) g ( n d ) (f*g)(n)=\sum_{d|n}f(d)*g(\frac nd)
相关性质:

  • 交换律: f g = g f f ∗ g = g ∗ f
    根据定义式可得
  • 结合律: ( f g ) h = f ( g h ) (f ∗ g) ∗ h = f ∗ (g ∗ h)
    展开
    ( ( f g ) h ) ( n ) = d n ( f g ) ( d ) h ( n d ) = d n ( k d f ( k ) g ( d k ) ) h ( n d ) = a b c = n f ( a ) g ( b ) h ( c ) \begin{aligned} ((f*g)*h)(n)&=\sum_{d|n}(f*g)(d)*h(\frac nd)\\ &=\sum_{d|n}(\sum_{k|d}f(k)*g(\frac dk))*h(\frac nd)\\ &=\sum_{a*b*c=n}f(a)*g(b)*h(c)\\ \end{aligned}
    同理 ( f ( g h ) ) ( n ) = ( ( g h ) f ) ( n ) = a b c = n g ( a ) h ( b ) f ( c ) (f ∗ (g ∗ h))(n)=((g*h)*f)(n)=\sum_{a*b*c=n}g(a)*h(b)*f(c)
    ( f g ) h = f ( g h ) (f ∗ g) ∗ h = f ∗ (g ∗ h)
  • 分配律: f ( g + h ) = f g + f h f ∗ (g + h) = f ∗ g + f ∗ h
    证明:
    ( ( g + h ) f ) ( n ) = d n ( g ( d ) + h ( d ) ) f ( n d ) = d n g ( d ) f ( n d ) + d n h ( d ) f ( n d ) = ( f g ) ( n ) + ( f h ) ( n ) = ( f g + f h ) ( n ) \begin{aligned} ((g+h)*f)(n)&=\sum_{d|n}(g(d)+h(d))*f(\frac nd)\\ &=\sum_{d|n}g(d)*f(\frac nd)+\sum_{d|n}h(d)*f(\frac nd)\\ &= (f ∗ g)(n) + (f ∗ h)(n)\\ &= (f ∗ g+ f ∗ h)(n)\\ \end{aligned}
  • 单位元 f ϵ = f f*\epsilon=f
    显然
  • f , g f,g 为积性函数,则 f g f*g 为积性函数,若 f , g f,g 为完全积性函数,则 f g f*g 为完全积性函数
    证明:设 F = f g F=f*g ,要证的是 F ( i j ) = F ( i ) F ( j ) F(ij)=F(i)*F(j)
    F ( i j ) = a b = i j f ( a ) g ( b ) F(ij)=\sum_{ab=ij}f(a)*g(b)
    F ( i ) F ( j ) = ( a 0 b 0 = i f ( a 0 ) g ( b 0 ) ) ( a 1 b 1 = j f ( a 1 ) g ( b 1 ) ) = a 0 a 1 b 0 b 1 = i j ( f ( a 0 ) f ( a 1 ) ) ( g ( b 0 ) g ( b 1 ) ) = a 0 a 1 b 0 b 1 = i j f ( a 0 a 1 ) g ( b 0 b 1 ) = F ( i j ) \begin{aligned} F(i)*F(j)&=\left(\sum_{a_0b_0=i}f(a_0)*g(b_0)\right)*\left(\sum_{a_1b_1=j}f(a_1)*g(b_1)\right)\\ &=\sum_{a_0a_1b_0b_1=ij}(f(a_0)*f(a_1))*(g(b_0)*g(b_1))\\ &=\sum_{a_0a_1b_0b_1=ij}f(a_0a_1)*g(b_0b_1)\\ &=F(ij) \end{aligned}
常见的狄利克雷卷积式子
  • d = 1 1 d=1*1
    d ( n ) = d n 1 d(n)=\sum_{d|n}1
  • σ = d 1 \sigma=d*1
    σ ( n ) = d n d \sigma(n)=\sum_{d|n}d
  • ϵ = μ 1 \epsilon=\mu*1
    ϵ ( n ) = d n μ ( d ) \epsilon(n)=\sum_{d|n}\mu(d)
    证明:
    n n k k 个相异质因子
    k = 0 k=0 ,那么结果为 1 1
    否则 d n μ ( d ) = i = 0 k ( 1 ) i ( k i ) = ( 1 1 ) k = 0 \begin{aligned} \sum_{d|n}\mu(d)&=\sum_{i=0}^k(-1)^i\dbinom{k}{i}\\ &=(1-1)^k\\ &=0 \end{aligned}
  • φ = μ I d \varphi=\mu*Id
    φ ( n ) = d n μ ( d ) n d \varphi(n)=\sum_{d|n}\mu(d)\frac nd
    证明:
    首先证明: φ 1 = I d \varphi*1=Id

    d n φ ( d ) = n \sum_{d|n}\varphi(d)=n
    yangxin2003的形象证明
    给定一个 n n ,枚举 1 n , 2 n n n \frac 1n,\frac 2n···\frac nn ,并将每个约分
    考虑枚举约分后的分母(即枚举 j j ), φ ( j ) \varphi(j) 即为 j j 为分母时的最简分数数量,对应上面的 n n 个数
    证完之后然后莫比乌斯反演(下面会提到)即可
Möbius inversion formula(莫比乌斯反演)

f = g 1 g = u f f=g*1\Leftrightarrow g=u*f
另一种表示方式:
如果多项式 f , g f,g 满足 f ( n ) = d n g ( d ) f(n)=\sum_{d|n}g(d)
那么也一定满足 g ( n ) = d n μ ( d ) f ( n d ) g(n)=\sum_{d|n}\mu(d)f(\frac nd)
反之也成立
证明:
f = g 1 f=g*1
两边卷上 μ \mu
μ f = μ g 1 \mu*f=\mu*g*1
整理
μ f = ϵ g = g \mu*f=\epsilon*g=g
g = μ f g=\mu*f
反过来同理

欧拉筛

每个数都只会被其最小的质因数筛到
复杂度 Θ ( n ) \Theta(n) ,适合筛各种积性函数

inline void getlist(const int listsize)
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    for(rg int i=2;i<=listsize;i++)
    {
        if(isprime[i]==1)prime[++primesize]=i;
        for(int j=1;j<=primesize&&(LL)i*(LL)prime[j]<=(LL)listsize;j++)
        {
           isprime[i*prime[j]]=0;
           if(i%prime[j]==0)break;
        }
    }
}
  • Tip:对于欧拉筛有一个小技巧,可以开桶记录每个数的最小质因子,那么就可以做到 Θ ( n ) \Theta(n) 预处理,单次 Θ ( l o g n ) \Theta(logn) 的质因数分解复杂度了
  • Tip:单次的分解质因数复杂度是 Θ ( n ) \Theta(\sqrt n) 的,枚举小于 n \sqrt n 的数,如果整除就除掉,如果最后剩下的值不为1,那么剩下的这个值也是一个质因数,次数为1
杜教筛

现在有个数论函数 f ( n ) f(n) ,现在要求 S ( n ) = i = 1 n f ( i ) S(n)=\sum_{i=1}^nf(i)
杜教筛的核心思想是:找到一个数论函数 g ( n ) g(n)
因为显然满足 i = 1 n d i f ( d ) g ( i d ) = i = 1 n g ( i ) S ( n i ) \sum_{i=1}^n\sum_{d|i}f(d)g(\frac id)=\sum_{i=1}^ng(i)S(\left\lfloor \frac ni\right\rfloor)
所以就有 S ( n ) S(n) 的递推式:
g ( 1 ) S ( n ) = i = 1 n ( f g ) ( i ) i = 2 n g ( i ) S ( n i ) g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\left\lfloor \frac ni\right\rfloor)

  • Tip:能用杜教筛的前提是找到了合适的 g ( n ) g(n) ,杜教筛能够筛某几种特定的积性函数,在下面会分别列举
常见杜教筛板子
  • φ ( n ) S ( n ) \varphi(n)的前缀和S(n)
    我们已经知道 φ 1 = I d \varphi*1=Id
    那么在 f = φ f=\varphi 的条件下, g = 1 g=1 无疑是最佳选择,
    那么,上面的递推式就变成了
    S ( n ) = i = 1 n i i = 2 n S ( n i ) S(n)=\sum_{i=1}^ni-\sum_{i=2}^nS(\left\lfloor \frac ni\right\rfloor)
    首先证明这个递推式里的元素数量是 Θ ( n ) \Theta(\sqrt n)
    解释:
    x a b = x a b 访 n i Θ ( n ) m = n 1 , 2 , m 1 , m , n m , n m 1 , n 2 , n 1 \because\left\lfloor\frac {\left\lfloor\frac xa\right\rfloor}b \right\rfloor=\left\lfloor\frac x{ab} \right\rfloor\\ \therefore所有被访问的元素为\left\lfloor\frac ni \right\rfloor\\ 元素数是\Theta(\sqrt n)的\\ 设m=\sqrt n\\ 这些元素是1,2···,m-1,m,\left\lfloor\frac nm\right\rfloor,\left\lfloor\frac n{m-1}\right\rfloor···,\left\lfloor\frac n2\right\rfloor,\left\lfloor\frac n1\right\rfloor
    然后考虑算法复杂度
    对于上面那个式子的第一项显然是 ( 1 + n ) n 2 \frac {(1+n)*n}2 ,计算是 Θ ( 1 ) \Theta(1)的
    对于第二项,刚才已经证明 n i \left\lfloor\frac ni \right\rfloor 的取值只有 Θ ( n ) \Theta(\sqrt n) 个,那么我们只要枚举每个取值,计算其贡献次数即可
    复杂度的式子是
    i = 1 n Θ ( i ) + i = 1 n Θ ( n i ) \sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt i)+\sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt{\frac ni})
    这个式子的结果是 Θ ( n 3 4 ) \Theta(n^{\frac 34})
    由于前面的 n \sqrt n 个值可以用线性筛跑出来,所以复杂度为
    n + i = 1 n Θ ( n i ) \sqrt n+\sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt{\frac ni})
    瓶颈在后一半,所以可以通过调整块大小来优化复杂度
    设我们筛前 k k 个,那么前面一项的复杂度为 Θ ( k ) \Theta(k) ,后面一项的复杂度为 Θ ( n k ) \Theta(\frac n{\sqrt k}) (这个的复杂度证明是根据微积分可得 i = 1 n Θ ( 1 i ) = Θ ( n ) \sum_{i=1}^n\Theta(\frac 1{\sqrt i})=\Theta(\sqrt n) ,然后带入得 Θ ( n ) Θ ( n k ) = Θ ( n k ) \Theta(\sqrt n)*\Theta(\sqrt {\frac nk})=\Theta(\frac n{\sqrt k}) ),总复杂度最优时
    k = n k , k 3 2 = n , k = n 2 3 k=\frac n{\sqrt k},k^{\frac 32}=n,k=n^{\frac 23}
    最优复杂度为 Θ ( n 2 3 ) \Theta(n^{\frac 23})
    代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
namespace fast_IO
{
    const int IN_LEN=10000000,OUT_LEN=10000000;
    char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
    inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
    inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
    inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
//#define getchar() getchar_()
//#define putchar(x) putchar_((x))
//#include<ctime>
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
//template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
    char cu=getchar();x=0;bool fla=0;
    while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
    while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
    if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
    if(x>=10)printe(x/10);
    putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
    if(x<0)putchar('-'),printe(-x);
    else printe(x);
}
const int MAX=2000000;
bool isprime[MAX+1];
int n,prime[MAX+1],primesize;LL phi[MAX+1],phi1[MAX+1];
inline void getlist(const LL listsize)
{
	memset(isprime,1,sizeof(isprime));
	isprime[1]=0,phi[1]=1;;
	for(rg int i=2;i<=listsize;i++)
	{
		if(isprime[i])prime[++primesize]=i,phi[i]=i-1;
		for(rg int j=1;j<=primesize&&(LL)i*prime[j]<=listsize;j++)
		{
			isprime[i*prime[j]]=0;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}
inline LL Val(const int x)
{
	if(x<=MAX)return phi[x];
	return phi1[n/x];
}
int main()
{
	getlist(MAX);
	for(rg int i=1;i<=MAX;i++)phi[i]+=phi[i-1];
	read(n);
	for(rg int i=min((int)sqrt(n),n/(MAX+1));i>=1;i--)
	{
		const int u=n/i;
		LL res=(LL)u*(u+1)/2;
		int limit=sqrt(u);
		for(rg int j=1;j<=limit;j++)res-=Val(u/j);
		limit++;
		for(rg int j=1;limit*j<=u;j++)res-=phi[j]*((u/j)-(u/(j+1)));
		phi1[i]=res;
	}
	print(Val(n));
	return flush(),0;
}
  • μ ( n ) \mu(n) 的前缀和 S ( n ) S(n)
    同样的,我们可以找到一个 g ( n ) g(n) ,没错又是 1 1 ,因为 μ 1 = ϵ \mu*1=\epsilon
    所以带入式子 S ( n ) = 1 i = 2 n S ( n i ) S(n)=1-\sum_{i=2}^nS(\left\lfloor \frac ni\right\rfloor)
    哇,这不是东西更少了吗,和上面一样的思路,复杂度 Θ ( n 2 3 ) \Theta(n^{\frac 23})
    代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
namespace fast_IO
{
    const int IN_LEN=10000000,OUT_LEN=10000000;
    char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
    inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
    inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
    inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
//#define getchar() getchar_()
//#define putchar(x) putchar_((x))
//#include<ctime>
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
//template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
    char cu=getchar();x=0;bool fla=0;
    while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
    while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
    if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
    if(x>=10)printe(x/10);
    putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
    if(x<0)putchar('-'),printe(-x);
    else printe(x);
}
const int MAX=2000000;
bool isprime[MAX+1];
int T,n;
int prime[MAX+1],primesize;LL mu[MAX+1],mu1[MAX+1];
inline void getlist(const LL listsize)
{
	memset(isprime,1,sizeof(isprime));
	isprime[1]=0,mu[1]=1;
	for(rg int i=2;i<=listsize;i++)
	{
		if(isprime[i])prime[++primesize]=i,mu[i]=-1;
		for(rg int j=1;j<=primesize&&(LL)i*prime[j]<=listsize;j++)
		{
			isprime[i*prime[j]]=0;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
}
inline LL Val(const int x)
{
	if(x<=MAX)return mu[x];
	return mu1[n/x];
}
int main()
{
	getlist(MAX);
	for(rg int i=1;i<=MAX;i++)mu[i]+=mu[i-1];
	read(n);
	for(rg int i=min((int)sqrt(n),n/(MAX+1));i>=1;i--)
	{
		const int u=n/i;
		LL res=1;
		int limit=sqrt(u);
		for(rg int j=1;j<=limit;j++)res-=Val(u/j);
		limit++;
		for(rg int j=1;limit*j<=u;j++)res-=mu[j]*((u/j)-(u/(j+1)));
		mu1[i]=res;
	}
	print(Val(n));
	return flush(),0;
}

其实代码差不太多


我是分割线,本博客由于博主实力受限,暂时停更


猜你喜欢

转载自blog.csdn.net/zhouyuheng2003/article/details/84798775