2021.12.13 莫比乌斯反演
https://www.cnblogs.com/yifusuyi/p/10186819.html
https://blog.csdn.net/Ivanzn/article/details/88641049
https://zhuanlan.zhihu.com/p/197411920
1. 前置知识
1.1 组合等式
组合意义:
\(n\) 个元素中取 \(r\) 个组合, \(r\) 为奇数的组合数目等于 \(r\) 为偶数的组合数目(包括 \(r=0\) )。
证明:
把 \(r\) 为奇数的组合和 \(r\) 为偶数的组合一一对应。
把所有组合分成含元素 \(a\) 的和不含元素 \(a\) 的。设 \(r\) 为奇数,若含有元素 \(a\) ,则去掉 \(a\) 之后对应且唯一对应 \(r-1\) 为偶数的组合,若不含元素 \(a\) ,则加上 \(a\) 之后对应且唯一对应 \(r+1\) 为偶数的组合。当 \(r\) 为偶数时同理。
1.2 莫比乌斯函数
1.3 莫比乌斯函数衍生的定理(结论1)
证:
当 \(n=1\) 时,
当 \(n>1\) 时,设 \(n=p_1^{a_1}p_2^{a_2}\cdots p_n^{a_n}\) , \(m=p_1p_2\cdots p_n\) ,则
1.4 狄利克雷卷积
1.4.1 各种数论函数
以下三种数论函数全部都是完全积性函数。
单位元: \(\epsilon(x) = [x = 1]\) 。
常函数: \(1(x)=1\) 。
恒等函数: \(id(x)=x\) 。
以下两种数论函数为积性函数但不是完全积性函数。
除数函数: \(d(n)\) ,n的因数个数
除数和函数: \(\sigma(n)\) ,n的所有因数之和
以上两个函数可以和到一个函数中,这个函数也叫除数函数,想不到吧?/滑稽
当 \(\lambda=0\) 时, \(\sigma_0(n)=d(n)\) ;
当 \(\lambda=1\) 时, \(\sigma_1(n)=\sigma(n)\) 。
1.4.2 定义
对于两个数论函数 \(f\) 、 \(g\) ,若 \(t=f*g\) ,则
1.4.3 性质
交换律:
结合律:
分配律:
数乘:
单位元
逆元:对于每一个 \(f(1)!=0\) 的函数 \(f\) ,都有 \(f*g=\epsilon\) 。 \(g\) 就是逆元。
2. 结论2
求
原式先枚举 \(i\) ,再枚举 \(i\) 的所有因数 \(d\) ,等价于先枚举 \(d\) ,再枚举小于等于n的所有倍数。即
3. 结论3
4. 乱七八糟的推论
4.1 \(d*\mu=1\)
证明:
4.2 \(\phi*1=id\)
4.3 \(id*\mu=\phi\)
证:
5. 练习题
请注意:long long的速度比int慢!!!
https://www.luogu.com.cn/problem/P1390
题意:
求
分析:
https://www.luogu.com.cn/blog/juruoHBr/solution-p1390
设 \(t=\frac{n}{d}\) ,则
最后的结果减去 \((i,i)=i\) 的和 \((i,j)=(j,i)\) 。
对于所有 \((i,j)=(j,i)\) ,只需要在减完上一条式子之后把答案除以2。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int long long
const int N=2e6+10;
int n,mu[N],is_prime[N],prime[N],top,sum[N];
inline void init(){
//for(int i=1;i<=n;i++)is_prime[i]=1;
mu[1]=1;
for(int i=2;i<=n;i++){
if(!is_prime[i])is_prime[i]=i,prime[++top]=i,mu[i]=-1;
for(int j=1;j<=top;j++){
if(prime[j]>is_prime[i]||i*prime[j]>n)break;
is_prime[i*prime[j]]=prime[j];
mu[i*prime[j]]=i%prime[j]?-mu[i]:0;
//如果 i%prime[j]==0 ,则说明至少含有两个相同素数
//否则就是 mu[i]*(-1)
}
}
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];//,cout<<mu[i]<<" ";cout<<endl;//
}
inline int calc(int n,int d){
n=n/d;
int fin=0;
for(int L=1,R=0;L<=n;L=R+1){
int tmp=n/L;
R=min(n,n/tmp);
fin+=(sum[R]-sum[L-1])*tmp*tmp;
}
return fin;
}
signed main(){
IOS;
cin>>n;
init();
int ans=0;
for(int i=1;i<=n;i++)ans+=i*calc(n,i);
//cout<<ans<<endl;//
ans-=(n+1)*n/2;
ans/=2;
cout<<ans;
return 0;
}
https://www.luogu.com.cn/problem/P6810
题意:
求
分析:
https://www.luogu.com.cn/blog/genshy/solution-p6810
https://www.luogu.com.cn/blog/quest233/solution-p6810
要求 \(n<=m\) ,不满足要求你就 swap
一下,反正不亏。
令 \(T=ek\) ,则
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
//#define int long long
const int N=2e6+10;
int d[N],f[N];
long long sum1[N],sum2[N];
int n,m,mod,is_prime[N],prime[N],top;
inline void init(){
d[1]=f[1]=is_prime[1]=1;
for(int i=2;i<=m;i++){
if(!is_prime[i])prime[++top]=i,f[i]=1,d[i]=2;
for(int j=1;j<=top&&i*prime[j]<=m;j++){
is_prime[i*prime[j]]=1;
if(i%prime[j]==0){
f[i*prime[j]]=f[i]+1;
d[i*prime[j]]=1ll*d[i]*(f[i*prime[j]]+1)/(f[i]+1);
//此时最小质因子个数为f[i]+1,因为这是在i的基础上才新找到的最小质因子
//所以此时因数的个数为(d[i]/(f[i]+1))*(f[i*prime[j]]+1)
break;
}
f[i*prime[j]]=1;
d[i*prime[j]]=1ll*d[i]*d[prime[j]];
}
}
}
signed main(){
IOS;
cin>>n>>m>>mod;
if(n>m)swap(n,m);
init();
for(int i=1;i<=n;i++)for(int j=1;j<=n/i;j++)sum1[i]=(sum1[i]+d[i*j])%mod;
for(int i=1;i<=m;i++)for(int j=1;j<=m/i;j++)sum2[i]=(sum2[i]+d[i*j])%mod;
long long ans=0;
for(int i=1;i<=n;i++)ans=(ans+1ll*sum1[i]*sum2[i]%mod)%mod;
cout<<ans;
return 0;
}
https://www.luogu.com.cn/problem/P2257
题意:
求
分析:
设 \(p_1,p_2,p_3,\cdots,p_{top}\) 均为质数。
令 \(T=p_dk\) ,则
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int long long
typedef long long ll;
const int N=1e7+10;
int t,m,n,mu[N],is_prime[N],prime[N],top;
ll sum[N],tot[N];
inline void init(){
mu[1]=1;
for(int i=2;i<=N-10;i++){
if(!is_prime[i])prime[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*prime[j]<=N-10;j++){
is_prime[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=top;i++)for(int j=1;j*prime[i]<=N-10;j++)tot[j*prime[i]]+=1ll*mu[j];
//for(int i=1;i<=10;i++)cout<<mu[i]<<" ";cout<<endl;
for(int i=1;i<=N;i++)sum[i]=sum[i-1]+tot[i];
//for(int i=1;i<=20;i++)cout<<tot[i]<<" ";cout<<endl;
}
signed main(){
IOS;
init();
cin>>t;
while(t--){
cin>>n>>m;
if(n>m)swap(n,m);
ll ans=0;
for(int L=1,R=0;L<=n;L=R+1){
R=min(n/(n/L),m/(m/L));
ans+=(n/L)*(m/L)*(sum[R]-sum[L-1]);
}
cout<<ans<<endl;
}
}
https://www.luogu.com.cn/problem/P2522
题意:
求
分析:
行吧,2021.12.12号考试是我傻,都推到第二步了愣是没想到莫比乌斯反演 ,无语中……
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const int N=5e4+10;
int t,mu[N],is_prime[N],prime[N],top;
ll sum[N];
inline void init(){
mu[1]=1;
for(int i=2;i<=N-10;i++){
if(!is_prime[i])prime[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*prime[j]<=N-10;j++){
is_prime[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=N-10;i++)sum[i]=sum[i-1]+1ll*mu[i];
//for(int i=1;i<=10;i++)cout<<mu[i]<<" ";cout<<endl;
//for(int i=1;i<=10;i++)cout<<sum[i]<<" ";cout<<endl;
}
inline int solve(int n,int m,int k){
if(!n||!m)return 0;
ll ans=0;
n/=k;m/=k;
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));
ans+=1ll*(m/L)*(n/L)*(sum[R]-sum[L-1]);
}
return ans;
}
signed main(){
IOS;
init();
cin>>t;
while(t--){
int a,b,c,d,k;
cin>>a>>b>>c>>d>>k;
ll ans=solve(b,d,k)-solve(b,c-1,k)-solve(a-1,d,k)+solve(a-1,c-1,k);
cout<<ans<<endl;
}
return 0;
}
https://www.luogu.com.cn/problem/P1447
题意:
求
分析:
令 \(T=dk\) ,则
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int long long
const int N=1e5+10;
int n,m,top,is_prime[N],prime[N];
long long phi[N],sum[N];
inline void init(){
phi[1]=1;
for(int i=2;i<=m;i++){
if(!is_prime[i])prime[++top]=i,phi[i]=i-1;
for(int j=1;j<=top&&i*prime[j]<=m;j++){
is_prime[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=1;i<=m;i++)sum[i]=sum[i-1]+phi[i];
//for(int i=1;i<=m;i++)cout<<phi[i]<<" ";cout<<endl;
//for(int i=1;i<=m;i++)cout<<sum[i]<<" ";cout<<endl;
}
signed main(){
IOS;
cin>>n>>m;
if(n>m)swap(n,m);
init();
long long ans=0;
for(int L=1,R=0;L<=n;L=R+1){
R=min(n/(n/L),m/(m/L));
ans+=1ll*(n/L)*(m/L)*(sum[R]-sum[L-1]);
}
cout<<ans*2-n*m;
return 0;
}
https://www.luogu.com.cn/problem/P1829
题意:
求
分析:
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int long long
const int N=1e7+10;
const int mod=20101009;
int n,m,top,is_prime[N],prime[N];
long long mu[N],sum[N];
inline void init(){
mu[1]=1;
for(int i=2;i<=m;i++){
if(!is_prime[i])prime[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*prime[j]<=m;j++){
is_prime[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=m;i++)sum[i]=(sum[i-1]+1ll*(mu[i]+mod)%mod*i%mod*i%mod)%mod;
}
inline int func(int x,int y){
return 1ll*((1+x)*x/2%mod)*((1+y)*y/2%mod)%mod;
}
inline int calc(int x,int y){
int fin=0;
for(int L=1,R=0;L<=min(x,y);L=R+1){
R=min(x/(x/L),y/(y/L));
fin=(fin+1ll*((sum[R]-sum[L-1])%mod)*(func(x/L,y/L)%mod))%mod;
}
return fin;
}
signed main(){
IOS;
cin>>n>>m;
if(n>m)swap(n,m);
init();
long long ans=0;
for(int L=1,R=0;L<=n;L=R+1){
R=min(n/(n/L),m/(m/L));
ans=(ans+1ll*((L+R)*(R-L+1)/2%mod)*calc(n/L,m/L)%mod+mod)%mod;
}
cout<<ans;
return 0;
}