蒟蒻的数论笔记
数论笔记
定义
一些规定
1.如无特殊标记,\(f_k(n)=f^k(n)\)
2.如无特殊说明,\(num(n,p)=max(k \in {p^k|n})\)
3.\([x]\)按照语境通常是向下取整的含义
4.\(\,p\,\)表示容易质数,\(\,P\,\)表示质数集,如无特殊说明,\(\,p_i\,\)表示第\(\,i\,\)大的质数
许多数论函数
欧拉函数\(\varphi(x)\):[1,n]中与n互质的数的个数
刘维尔函数
莫比乌斯函数
约数个数函数
元函数
恒等函数
单位函数
约数和函数
积性函数:
完全积性函数:
狄利克雷卷积
定义
设\(f,g\)为积性函数
则\(f\,\ast\,g=\sum_{d|n}f(d)g(\frac{n}{d})\)
狄利克雷卷积的一些性质
\(f\,\ast\,\epsilon\,=\,f\)
\(f\,\ast\,g=g\,\ast\,f\)
\(f\,\ast\,(g\,\ast\,h)=(f\,\ast\,g)\ast\,h\)
\((f+g)\,\ast\,h=\,f\,\ast\,h\,+\,g\,\ast\,h\)
定理
小知识
常见结论
神秘小知识
(1)
证明如下:
构造一个二元数列\(\,(h,k)\,\)使得\(\,(h,k)=1\,\and\,k\mid n\,\and\,1\leq h<k\),特殊地,\((1,1)\)也被认为是合法的
构造另一个二元数列\(\,(i,n)\,\)其中\(\,1\leq i\leq n\),
对于\(\,(h,k)\,\)考虑其到\(\,(i,n)\,\)的映射,
不难发现\(\,(h,k)\rightarrow (\frac{hn}{k},n)\)
可以得到\(\,|(h,k)|\leq|(i,n)|\,\)
再考虑\(\,(i,n)\,\)到\(\,(h,k)\,\)的映射
可以发现\(\,|(i,n)|\leq|(h,k)|\,\)
放缩得\(\,|(i,n)|=|(h,k)|\,\)
显然有\(\,|(i,n)|=n\,\),所以\(\,|(h,k)|=n\,\)
结合定义知\(k=d\Rightarrow (h,k)=\varphi(d)\),即\(|(h,k)|=\sum_{d\mid n}\varphi(d)\)
得证
(2)
证明如下
若\(n\neq1\rightarrow n=\prod p_i^{a_i}\)
由\(\mu\,\)的定义知,若\(\,\,\exists\,num(m,p)>1\rightarrow \mu(m)=0\)
故而我们只考虑\(\,\,\prod\limits_{i=1}^{\lambda(n)}[num(m,p_i)\leq 1]=1\,\)的\(\,m\,\),下面的\(\,m\,\)都满足这一性质
设
就是说\(\,S_i\,\)考虑有\(\,i\,\)个质因子的\(\,m\,\)的总贡献,\(\,L_i\,\)表示这样的\(\,m\,\)的个数,特殊地,我们有\(L_0=S_0=1\),也就是\(\,m=1\,\)的贡献
由组合数的知识容易得到
考虑用\(\,L_i\,\)来表达\(\,I\,\ast\,\mu\,\),简单带入可得
考虑构造函数
所以有
综上,得证
(3)
\(gcd(n,m)=1\rightarrow\varphi(nm)=\varphi(n)\varphi(m)\quad\)也就是说欧拉函数是积性函数,但不是完全积性函数
(4)
杜教筛的构造
要求\(\,f\,\)的前缀和,构造一个很好求前缀和的函数\(\,h\,\)和一个很好求前缀和的辅助函数\(\,g\,\),使得
按狄利克雷卷积的定义展开
考虑用\(\,S_h\,\)表示\(\,S\),于是考虑交换求和符号,使得\(\,g\,\)和\(\,f\,\)分离:
发现\(\,\frac{n}{1}=n\,\),所以我们把右边第一项提出来:
整理得
由于构造的\(S_h(n)\)是容易求得的,即可以在低于线性的时间内求出(实际上很多时候都是\(\,\Theta(1)\,\)的),
\(\,g(1)\,\)也显然可以在\(\,\Theta(1)\,\)的时间里求出,所以只需要在低于线性的时间里求\(\,g(d)S(\frac{n}{d})\,\)的除去第一项的前缀和
考虑使用整除分块,则转化为求\(\,g\,\)在不超过\(\,2\sqrt n\,\)段上的和,前缀和即可,
对于\(\,S([\frac{n}{d}])\,\)项,我们直接递归,暴力地预处理出\(n^{\frac{2}{3}}\)个前缀和即可
复杂度分析
下文考虑中均认为求\(\,f,g\,\)的前缀和是\(\,\Theta(1)\,\)的
运用杜教筛,我们把求\(\,S(n)\,\)转化为了求所有的\(\,S(\frac{n}{d})\,\),本质上只有\(\,2\sqrt n\,\)种取值,忽略常数后,我们设杜教筛的复杂度为\(\,T(n)\,\),可得方程
含义为,求前n项前缀和的复杂度是\(\,\)整除分块的复杂度+处理出每个\(\,S(\frac{n}{d})\,\)和\(\,S(d)\,\)的复杂度
这里我们默认了\(\,n\,\)超出了预处理的前缀和,但\(\,\frac{n}{d}\,\)显然可能是被预处理过的值,所以需要考虑预处理,设预处理了\(\,k\,(k\geq\sqrt n)\,\)个,那么总的复杂度为:
注意到所有\(\,T(i)\,\)都已经被预处理了,可以\(\,\Theta(1)\,\)得到,复杂度为\(\,\Theta(\sqrt n)\,\),
接着考虑\(\,T(\frac{n}{i})\,\)的处理,考虑继续展开,注意此时不需要再预处理了:
上式最后的\(\,\sum\,\)含义为一个大于\(\,k\,\)的值迭代到\(\,k\,\)以内的迭代次数
令总复杂度为\(\,D=k+T(n)\,\),选\(\,k\,\)为主元,考虑其极值,得
最终的复杂度为\(\,\Theta(n^\frac{2}{3})\).
(5)
莫比乌斯反演
证明如下
得证
积性函数
(6)
对于任意积性函数\(f\,\)有
有算数基本定理和积性函数的定义容易推出
(7)对于任意完全积性函数\(f\,\)有
若积性函数\(f\,\)满足上式,则\(f\,\)也是完全积性函数
(8)
积性函数的神秘性质
由算数基本定理容易推出
(9)
由结论1得:
考虑消去其中的\(\,I\,\),利用结论2,两边同卷\(\,\mu\):
Powerful Number 筛
个人觉得比上面两种筛法都简单
先定义powerful number为\(\forall n,\forall p\in P\,\and p\mid n,p^2\mid n\)
说人话就是所有质因子次数不小于2的数
还是求积性函数的前缀和,构造函数\(g,g(p)=f(p)\),并使得\(\,g\,\)的前缀和容易求出
令
有
考虑展开卷积,得
考虑\(\,g\,\)的前缀和是容易求出的,交换求和号
这依然是\(\,\Theta(n)\,\)的,但因为\(\,h\,\)是积性函数并且\(\,h(p)=0\),所以\(\,\forall h(n)\neq 0,n\in Powerful\ Number\)
考虑\(\,Powerful\ Number\,\)的数量,以下的\(\,q\,\)是\(Powerful\ Number\)
由定义知
上文的\(\,p_i\,\)仅表示\(\,q\,\)的质因子
不难发现
那么
记\(\,power(n)=[n\in Powerful\ Number]\,\),那么powerful number的数目就是\(\,power()\,\)的前缀和
考虑枚举\(\,A\),计算对于的贡献,为了不算重,应该只枚举\(1-\sqrt n\),那么
那么就只需要求出\([1,n]\)中的所有powerful number,然后就可以\(\Theta(F\sqrt n)\)求出\(\,f\,\)的前缀和,其中\(\,F\,\)是求\(\,g\,\)的前缀和的复杂度
接下来介绍一个小技巧:
观察\(f=g\,\ast\,h\),发现\(f\,\ast\,g^{-1}=\epsilon\,\ast\,h=h\),其中\(g^{-1}\,\ast\,g=\epsilon\)
所以只要构造出\(\,g\,\)就可以求出\(\,h\),减小了构造的工作量
powerful number筛的时间复杂度和思维难度都有一定优势,但其辅助函数难以构造,使得很多问题不能用其解决
真定理
1.欧拉定理:
特殊地,\(gcd(a,p)=1\,\)时,有\(\,\,a^k\equiv\,a^{k\mod\varphi(p)}(mod\,\,p)\)
注意,使用时应当判断\(\,k\,\)与\(\varphi (p)\)的大小
2.费马小定理
其实就是欧拉函数的性质在欧拉定理中的应用:
代码
封装好了一些基本的东西
卢卡斯定理没有过
class MyMath
{
public:
vector<int> prime;
vector<int> phi;
vector<int> mu;
template<typename Tp_> inline Tp_ inv(Tp_ x,Tp_ p) {return pow(x,-1,p);}
inline bool is_prime(ll x)
{
if(x<0) x=-x;
if(!prime.empty())
if((*prime.rbegin())*(*prime.rbegin())>=x)
{
for(vector<int>::iterator it=prime.begin();(*it)*(*it)<=x&&it!=prime.end();++it)
if(!(x%(*it))) return false;
return true;
}//surely a bit faster,almost log(n)
for(ll i(2);i*i<=x;++i)
if(!(x%i)) return false;
return true;
}//n^0.5 hardly used
inline ll pow(ll a,ll x,ll p)
{
if(x==0) return 1;
if(x>0)
{
ll ret=1;
while(x) ret=(x&1?a*ret%p:ret),x>>=1,a=a*a%p;
return ret;
}
else
{
if(!phi.empty())
if(phi.size()>p)
return pow(a,x%phi[p]+phi[p],p);
ll ph=Phi(p);
return pow(a,x%ph+ph,p);
}
}//maybe log,n^0.5 when using Phi()
template <typename Tp_> inline Tp_ gcd(Tp_ x,Tp_ y)
{
if(x>y) swap(x,y);
if(x==0) return (y?y:1);
return gcd(y%x,x);
}//almost log
template <typename Tp_> inline Tp_ lcm(Tp_ x,Tp_ y) {return x/gcd(x,y)*y;}
inline int ex_gcd(int a,int b,int c,int &p,int &q)
{
int g=ExEuclid(a,b,p,q);
if(c%g) return p=0,q=0;
g=c/g,p*=g,q*=g;
return 1;
}//a*p+b*q=c(mod p),about log,maybe
template<typename Tp_> inline Tp_ Phi(Tp_ x)
{
Tp_ tmp=x,ret=x;
for (Tp_ i=2;i*i<=x;++i)
if (tmp%i==0)
{
ret=ret-ret/i;
while (tmp%i==0) tmp/=i;
}
if(tmp>1) ret-=ret/tmp;
return ret;
}//n^0.5
template<typename Tp_> inline Tp_ Lucas(Tp_ n,Tp_ m,Tp_ p)
{
if(m==0) return 1;
Tp_ np=n%p,mp=m%p;
if(np<mp) return 0;
mp=min(np-mp,mp);
Tp_ p1=1,p2=1;
for( Tp_ i = 0 ; i < mp ; ++i )
p1=p1*(n-i)%p,
p2=p2*(i+1)%p;
return (p1*pow(p2,p-2)%p)*Lucas(n/p,m/p,p)%p;
}//p must be a prime
inline void sieve(const int capN)
{
bool *isp;
isp=new bool [capN+5];
memset(isp,0,sizeof(bool)*(capN+4));
if(!prime.empty()) prime.clear();
for(int i(2);i<=capN;++i)
{
if(!isp[i]) prime.emplace_back(i);
for(vector<int>::iterator it=prime.begin();it!=prime.end();++it)
{
if(i*(*it)>capN) break;
isp[i*(*it)]=1;
if(!(i%(*it))) break;
}
}
delete isp;
}//O(n) and need more place
inline void phi_sieve(const int capN)
{
if(!prime.empty()) prime.clear();
phi.resize(capN+4,0),phi[1]=1;
for(int i(2);i<=capN;++i)
{
if(!phi[i])
prime.emplace_back(i),
phi[i]=i-1;
for(vector<int>::iterator it=prime.begin();it!=prime.end();++it)
{
if(i*(*it)>capN) break;
if(!(i%(*it)))
{
phi[i*(*it)]=phi[i]*(*it);
break;
}
else phi[i*(*it)]=phi[i]*(*it-1);
}
}
}//cna get phi while finding primes in [1,capN]
private:
inline int ExEuclid(int a,int b,int &p,int &q)
{
if(b==0) return p=1,q=0,a;
int d=ExEuclid(b,a%b,p,q);
int tmp=p;
p=q,q=tmp-a/b*q;
return d;
}//a help function of ex_gcd
}M;