狄利克雷卷积与数论函数:
狄利克雷卷积写作:
\[f(x)*g(x)=(f*g)(x) \]定义:
\[(f*g)(x)=\sum_{d|n}^nf(d)*g(n/d) \]也可以写作:
\[(f*g)(x)=\sum_{x*y=n}^nf(x)*g(y) \]狄利克雷卷积满足交换律与结合律:
\[\begin{cases} (f*g)(n)=\sum_{x*y=n}^n\limits f(x)*g(y)=\sum_{x*y=n}^n\limits g(x)*f(y)=(g*f)(n)\\ \\ ((f*g)*h)(n)=\sum_{x*y*z=n}^n\limits f(x)*g(y)*h(z)=(f*(g*h))(n)\\ \end{cases} \]狄利克雷卷积是一个对称的结构
一些简单的数论函数:
定义:积性函数:
对于一个函数 \(F\) , 如果 \(gcd(a,b)=1\) 时有\(F(ab)=F(a)F(b)\),则该函数是积性函数。
定义:完全积性函数:
对于任意的整数 \(a\) 和 \(b\) 有 \(F(ab)=F(a)F(b)\)
很明显,完全积性函数∈积性函数。
一些常见的积性函数:
恒等函数,无论 \(n\) 是啥,它永远等于1:
\[I(n)=1 \]元函数,当 \(n=1\) 时,函数值为 \(1\),否则为 \(0\):
\[e(n)=[n==1] \]单位函数:
\[id(n)=n \]幂函数,单位函数是它的特殊情况:
\[id^k(n)=n^k \]欧拉函数,小于n的整数中,与n互质的数的个数:
\[\varphi(n)=\sum_{i=1}^{n-1}[gcd(i,n)==1] \]以及下文要用到的莫比乌斯函数 \(\mu(n)\)
积性函数的一些性质:
\[\begin{cases} F(1)=F(1)F(1)→ F(1)=1\\ \\ F(x)=F(p_1^{k1})F(p_2^{k2})...F(p_m^{km})\\ \end{cases}\]积性函数的逆也是积性函数:
首先,定义函数在狄利克雷卷积意义下的逆:
考虑:
\[(F*e)(n)=\sum_{d|n}^n[n/d==1]*F(d) \]即:
\[(F*e)(n)=\sum_{d|n}^n[d==n]*F(d) \]即:
\[F*e=F \]那么,如果 \(G*F=e\) ,我们就说 \(F\) 与 \(G\) 互逆
\[G*F=e ⇔ G=F^{-1} \]下证:
\[\begin{cases} F(ab)=F(a)F(b)\\ \\ gcd(a,b)==1\\ \end{cases} → F^{-1}(ab)=F^{-1}(a)F^{-1}(b)\]因为:
\[e=\sum_{d|n}^nF(d)F^{-1}(n/d) \]考虑归纳证明:
当 \(a=1\) 或 \(b=1\) 时:
若 \(a,b\) 均等于 \(1\) ,\(e(1)=F(1)*F^{-1}(1)=1\)
而 \(F(1)=1\) ,因此 \(F^{-1}(1)=1\)
当 \(a,b>1\) 时:
设,对于 \(\forall a'<a,b'<b\),都有 \(F^{-1}(a'b')=F^{-1}(a')F^{-1}(b')\)
下证 \(F^{-1}(ab)=F^{-1}(a)F^{-1}(b)\)
显然,有:
\[\sum_{d|n,d!=1}^nF(d)F^{-1}(n/d)+F(1)F^{-1}(n)=\sum_{d|n}^nF(d)F^{-1}(n/d) \]即:
\[\sum_{d|n}^nF(d)F^{-1}(n/d)-\sum_{d|n,d!=1}^nF(d)F^{-1}(n/d)=F^{-1}(n) \]有:
\[F^{-1}(ab)=\sum_{d|ab}^{ab}F(d)F^{-1}(ab/d)-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \] \[F^{-1}(ab)=e(ab)-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \] \[F^{-1}(ab)=0-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \] \[=-\sum_{d|ab,d!=1}^{ab}F(d)F^{-1}(ab/d) \] \[=-\sum_{i|a}^{a}\sum_{j|b,ij!=1}^{b}F(ij)F^{-1}(ab/ij) \] \[=-\sum_{i|a}^{a}\sum_{j|b,ij!=1}^{b}F(i)F^{-1}(j)F^{-1}(a/i)F(b/j) \] \[=-\sum_{i|a}^{a}F(i)F^{-1}(a/i)\sum_{j|b,ij!=1}^{b}F^{-1}(j)F(b/j) \] \[=F(1)F^{-1}(a)F^{-1}(1)F(b)-\sum_{i|a}^{a}F(i)F^{-1}(a/i)\sum_{j|b}^{b}F^{-1}(j)F(b/j) \] \[=F^{-1}(a)F(b)-e(a)*e(b) \] \[=F^{-1}(a)F(b) \]证毕
莫比乌斯反演:
设:
\[F(n)=\sum_{d|n}^nf(d) \]显然:
\[F(n)=\sum_{d|n}^nf(d)*1 \]即:
\[F=I*f \]那么:
\[f=I^{-1}*F \]现在只需要求 \(I^{-1}\) 即可通过 \(F\) 反演出 \(f\) 。
令 \(\mu=I^{-1}\),显然 \(\mu\) 是积性函数。
先从 \(\mu(p^k)\) 入手:
当 \(k=0\) 时:
\[e(1)=I(1)*\mu(1)=1 \]因此 \(\mu(1)=1\)
\(k=1\) 时:
\[e(p)=I(1)*\mu(p)+I(p)*\mu(1)=0 \] \[\mu(p)+\mu(1)=0 \] \[\mu(p)=-1 \]\(k=2\) 时:
\[e(p^2)=I(1)*\mu(p^2)+I(p)*\mu(p)+I(p^2)*\mu(1)=0 \] \[\mu(p^2)+\mu(p)+\mu(1)=0 \] \[\mu(p^2)+0=0 \] \[\mu(p^2)=0 \]\(k>2\) 时,数学归纳法可证 \(\mu(p^k)=0\)
因此,若:
\[n=pri_1^{k_1}*pri_2^{k_2}*... \]则:
\[\mu(n)=\begin{cases} 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\ \exists\ k_i>1]\\ (-1)^{\sum k}\ \ \ \ \ [\ \forall\ k_i<=1]\\ \end{cases}\]这就有了莫反的第一种形式:
\[F(n)=\sum_{d|n}^nf(d) ⟺ f(n)=\sum_{d|n}^n\mu(d)F(n/d)\ \ \ (1) \]也是最常用的形式。
还有倍数形式:
\[F(n)=\sum_{n|d}^nf(d) ⟺ f(n)=\sum_{n|d}^n\mu(d)F(d/n)\ \ \ (2) \]可以左式代入右式中证明,更简单的方法是像二项式反演那样,直接把转移写成矩乘的形式,转置一下即可。
以上两个式子由于转移方向单一,而且复杂度没什么优化,所以一般可以直接一层容斥解决,不需要莫反
更有用的是嵌入式莫反:
因为:
\[I*\mu=e \]所以:
\[\sum_{d|n}^n\mu(d)=[n=1] \]由于:
\[[n|m][m/n=1]=[n=m] \]所以:
\[[n|m]\sum_{d|m/n}^{m/n}\mu(d)=[n=m] \]莫比乌斯反演与整除分块:
- (1)求:
我们使用嵌入式反演,有:
\[\sum_{d|n}^n\mu(d)=[n=1] \] \[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}^{gcd(i,j)}\mu(d) \]由于:
\[[d|gcd(i,j)]=[d|i][d|j] \]因此:
\[\sum_{i=1}^n\sum_{j=1}^m[gcd=1]=\sum_{d}^{min(n,m)}\mu(d)\sum_{d|i}^n\sum_{d|j}^m1 \] \[\sum_{i=1}^n\sum_{j=1}^m[gcd=1]=\sum_{d}^{min(n,m)}\mu(d) \lfloor n/d \rfloor \lfloor m/d \rfloor \]预处理前缀和,整除分块即可在 \(O(\sqrt n)\) 时间内求解
- (2)求:
我们使用嵌入式反演,有:
\[[n|k]\sum_{d|k/n}^{k/n}\mu(d)=[n=k] \] \[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)|k]\sum_{d|k/gcd(i,j)}^{k/gcd(i,j)}\mu(d) \]因此:
\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\mu(d)\sum_{d|i}^{n/k}\sum_{d|j}^{m/k}1 \] \[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\mu(d) \lfloor \frac n{kd} \rfloor \lfloor \frac m{kd} \rfloor \]- (3)求:
即:
\[\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k] \] \[=\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)|k]\sum_{d|k/gcd(i,j)}^{k/gcd(i,j)}\mu(d) \] \[=\sum_{k \in prime}^{min(n,m)}\sum_{d=1}^{min(n/k,m/k)}\mu(d)\sum_{d|i}^{n/k}\sum_{d|j}^{m/k}1 \] \[=\sum_{k \in prime}^{min(n,m)}\sum_{d=1}^{min(n/k,m/k)}\mu(d)\sum_{kd|i}^{n}\sum_{kd|j}^{m}1 \]另 \(d=kd\) ,枚举新的 \(d\):
\[\sum_{k \in prime}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]=\sum_{d=1}^{min(n,m)}\sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k)\sum_{d|i}^{n}\sum_{d|j}^{m}1 \] \[=\sum_{d=1}^{min(n,m)}\sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k) \lfloor n/d \rfloor \lfloor m/d \rfloor \] \[=\sum_{d=1}^{min(n,m)} \lfloor n/d \rfloor \lfloor m/d \rfloor \sum_{k \in prime,k|d}^{min(n,m)}\mu(d/k) \]将预处理 \(\mu(d)\) 的前缀和改为预处理 \(\sum_{k \in prime,k|d}^{min(n,m)}\limits \mu(d/k)\) 即可。
- (4)求:
显然:
\[\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)}=\prod_{i=1}^n\prod_{j=1}^n\frac{i*j}{gcd(i,j)^2} \] \[=(\prod_{i=1}^n\prod_{j=1}^ni*j)*(\prod_{i=1}^n\prod_{j=1}^ngcd(i,j))^{-2} \] \[=(\prod_{i=1}^n(i^n*n!))*(\prod_{k=1}^{n}k^{-2*(\sum_{i=1}^{n/k}\limits \sum_{j=1}^{n/k}\limits [gcd(i,j)=k])}) \] \[=(n!)^{2n}*(\prod_{k=1}^{n}k^{-2*(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)}) \]如果对 \(\lfloor \frac n{kd} \rfloor\) 整除分块,分别对每个 \(d\) 求出对应的 \(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)\),时间复杂度就是 \(O(n \sqrt n)\) 的。
我们可以直接对 \(n/k\) 整除分块,求出 \(\prod_{k=1}^{n}k^{-2*(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)}\) ,时间复杂度就约为 \(O(\sqrt n*\sqrt n)=O(n)\)
- (5)求:
有等式:
\[d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] \]对于每一个质因数讨论,令 \(k_x\) 表示最大的 \(prime^k|x\)。
用 \(d\) 表示所枚举的约数,设 \(k_i>k_j\)。
那么若\(k_y=0\),则 \(k_d=k_x\) ,若 \(k_x=0\),则 \(k_d=k_i+k_y\)。
显然这样可以表示出所有约数,等式成立。
\[\sum_{i=1}^n \sum_{j=1}^md(ij)=\sum_{i=1}^n \sum_{j=1}^m\sum_{x|i}\sum_{y|j}[gcd(x,y)==1] \] \[=\sum_{i=1}^n \sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|gcd(x,y)}\mu(d) \] \[=\sum_{x=1}^n \sum_{y=1}^m\lfloor \frac {n}{x} \rfloor\lfloor \frac {m}{y} \rfloor \sum_{d|gcd(x,y)}\mu(d) \] \[=\sum_{i=1}^n \sum_{j=1}^m\lfloor \frac {n}{i} \rfloor\lfloor \frac {m}{j} \rfloor \sum_{d|gcd(x,y)}\mu(d) \] \[=\sum_d^{min(n,m)}\mu(d)\sum_{i=1}^{\lfloor \frac n d\rfloor }\sum_{j=1}^{\lfloor \frac m d \rfloor}\lfloor \frac {n}{id} \rfloor\lfloor \frac {m}{jd} \rfloor \] \[=\sum_d^{min(n,m)}\mu(d)\sum_{i=1}^{\lfloor \frac n d\rfloor }\lfloor \frac {n}{id} \rfloor\sum_{j=1}^{\lfloor \frac m d \rfloor}\lfloor \frac {m}{jd} \rfloor \]整除分块即可
[SDOI2008] 仪仗队
#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=5e4;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m){
long long res=0;
for(int l=1,r=0;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=1ll*(mu[r]-mu[l-1])*(n/l)*(m/l);
}return res;
}
int main(){
init();
scanf("%d",&q);if(q==1){puts("0");return 0;}
printf("%lld",solve(q-1,q-1)+2);
// scanf("%d",&q);
// while(q--){
// int n,m;
// scanf("%d%d",&n,&m);
// }
return 0;
}
[POI2007]ZAP-Queries
#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=5e4;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m,int d){
long long res=0;
for(int l=1,r=0;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=1ll*(mu[r]-mu[l-1])*(n/l/d)*(m/l/d);
}return res;
}
int main(){
init();
scanf("%d",&q);
while(q--){
int n,m,d;
scanf("%d%d%d",&n,&m,&d);
printf("%lld\n",solve(n,m,d));
}
return 0;
}
YY的GCD
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
long long mu[10000005],sum[10000005],f[10000005];
int pri[10000005],top;
bool vis[10000005];
inline void init(){
mu[1]=1;
for(int i=2;i<=1e7;i++){
if(!vis[i])pri[top++]=i,mu[i]=-1;
for(int j=0;j<top&&i*pri[j]<=1e7;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=0;i<top;i++){
for(int j=1;j*pri[i]<=1e7;j++)f[j*pri[i]]+=mu[j];
}
for(int i=1;i<=1e7;i++)sum[i]=sum[i-1]+f[i];
}
long long solve(){
long long res=0;
if(n>m)swap(n,m);
for(int l=1,r=0;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
}return res;
}
int main(){
init();//puts("000");
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
printf("%lld\n",solve());
}
return 0;
}
Product
#include<bits/stdc++.h>
using namespace std;
long long fac;
const long long md=104857601,phi=104857600;
int pri[1000005],top,mu[1000005];
bool vis[1000005];
inline void init(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*pri[j]<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
fac=1;
for(int i=1;i<=n;i++)fac=fac*i%md;
for(int i=1;i<=n;i++)mu[i]+=mu[i-1];
}
inline long long pwr(long long x,long long y){
long long res=1;
while(y){
if(y&1)res=res*x%md;
x=x*x%md;y>>=1;
}return res;
}
inline long long calc2(int n){
long long res=0;
for(int l=1,r=0;l<=n;l=r+1){
r=n/(n/l);
res=(res+1ll*(n/l)*(n/l)%phi*(mu[r]-mu[l-1]))%phi;
}return (res+phi)%phi;
}
inline long long calc(int n){
long long res=1;
for(int l=1,r=0;l<=n;l=r+1){
r=n/(n/l);fac=1;
for(int i=l;i<=r;i++)fac=fac*i%md;
res=res*pwr(fac*fac%md,calc2(n/l))%md;
}return res;
}
int main(){
int n;
scanf("%d",&n);
init(n);
long long ans=pwr(fac*fac%md,n);
printf("%lld",ans*pwr(calc(n),md-2)%md);
return 0;
}
[SDOI2015]约数个数和
#include<bits/stdc++.h>
using namespace std;
int T;
long long mu[50005],s[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=50000;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*pri[j]<=50000;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)continue;
mu[i*pri[j]]=-mu[i];
}mu[i]+=mu[i-1];
}
for(int i=1;i<=50000;i++){
for(int l=1,r;l<=i;l=r+1){
r=i/(i/l);
s[i]+=i/l*(r-l+1);
}
}
}
inline long long solve(int n,int m){
long long res=0;
for(int l=1,r;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=(mu[r]-mu[l-1])*s[n/l]*s[m/l];
}return res;
}
int main(){
scanf("%d",&T);init();
while(T--){
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",solve(n,m));
}
return 0;
}