【暖*墟】#数论# 莫比乌斯反演的学习与练习

 

莫比乌斯反演的应用范围

 

一些函数很难直接求值,而容易求出其倍数和或约数和,那么可以通过莫比乌斯反演求得原函数的值。

 

积性函数

 

定义:若 gcd(x,y)=1 ,且 f(xy)=f(x)f(y),则 f(n) 为积性函数。

性质:若 f(x) 和 g(x) 均为积性函数,则以下函数也为积性函数。

 

常见积性函数

 

Dirichlet 卷积

 

 

  • Dirichlet 卷积满足交换律、结合律、分配律。


其中 ε 为 Dirichlet 卷积的单位元(任何函数卷 ε 都为其本身)。

 

 

莫比乌斯函数

 

 

 

其中最重要的性质就是

 

void get_mu(int n){

mu[
1]=1; for(int i=2;i<=n;i++){
if(!vis[i]) primes[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&primes[j]*i<=n;j++){
vis[primes[j]
*i]=1;
if(i%primes[j]==0) break;
else mu[i*primes[j]]=-mu[i]; } } }

 

莫比乌斯反演

 

 

  • 公式可以进一步转化为:

 

相关习题练习

 

T1:【p3455】ZAP / 【p4450】双亲数
#include <cmath>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

//【p3455】ZAP
// 求∑(i=1~n)∑(j=1~m)[gcd(x,y)=d]

// 设f(d)为 gcd(i,j)=d 的个数,F(n)为 gcd(i,j)=d和d的倍数 的个数。
// 即:f(d)=∑(i=1~n)∑(j=1~m)[gcd(i,j)=d],F(n)=∑(n|d)f(d)=⌊N/n⌋⌊M/n⌋。
// 则可以得到:f(n)=∑(n|d) μ(⌊d/n⌋)*F(d)。

// 接下来的推导公式见:http://www.cnblogs.com/peng-ym/p/8652288.html

const int N=10000019;

bool vis[N]; int primes[N],cnt=0,mu[N],g[N]; ll sum[N];

void get_mu(int n){
    mu[1]=1; for(int i=2;i<=n;i++){
        if(!vis[i]) primes[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&primes[j]*i<=n;j++){
            vis[primes[j]*i]=1;
            if(i%primes[j]==0) break;
            else mu[i*primes[j]]=-mu[i];
        }
    } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
}

int main(){
    int T,n,m,d; cin>>T; get_mu(50000);
    while(T--){
        scanf("%d%d%d",&n,&m,&d); n=n/d,m=m/d;
        ll ans=0; for(int l=1,r;l<=min(n,m);l=r+1){
            r=min(n/(n/l),m/(m/l)); //整除分块
            ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
        } cout<<ans<<endl; //满足gcd(x,y)=d的(x,y)对数
    }
}
【p3455】ZAP // 求 ∑(i=1~n)∑(j=1~m)[gcd(x,y)=d]

 

T2:【p2522】problem B
  • ZAP+简单容斥原理(类似于二维前缀和的容斥):

ans=Ans((1,b),(1,d))−Ans((1,b),(1,c−1))−Ans((1,a−1),(1,d))+Ans((1,a−1),(1,c−1))

#include <cmath>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

//【p2522】problem B //'ZAP'的一般情况:求∑(i=a~b)∑(j=c~d)[gcd(x,y)=k]

// 设f(d)为 gcd(i,j)=d 的个数,F(n)为 gcd(i,j)=d和d的倍数 的个数。
// 即:f(d)=∑(i=1~n)∑(j=1~m)[gcd(i,j)=d],F(n)=∑(n|d)f(d)=⌊N/n⌋⌊M/n⌋。
// 则可以得到:f(n)=∑(n|d) μ(⌊d/n⌋)*F(d)。

// ZAP+简单容斥原理即可(类似于二维前缀和的容斥):
// ans=Ans((1,b),(1,d))−Ans((1,b),(1,c−1))−Ans((1,a−1),(1,d))+Ans((1,a−1),(1,c−1))

const int N=10000019;

bool vis[N]; int primes[N],cnt=0,mu[N],k; ll sum[N];

void get_mu(int n){
    mu[1]=1; for(int i=2;i<=n;i++){
        if(!vis[i]) primes[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&primes[j]*i<=n;j++){
            vis[primes[j]*i]=1;
            if(i%primes[j]==0) break;
            else mu[i*primes[j]]=-mu[i];
        }
    } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
}

ll calc(int n,int m){ n=n/k,m=m/k;
    ll ans=0; for(int l=1,r;l<=min(n,m);l=r+1){
        r=min(n/(n/l),m/(m/l)); //整除分块
        ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
    } return ans; //1~n,1~m,满足gcd(x,y)=k的(x,y)对数
}

int main(){ int T,a,b,c,d; cin>>T; get_mu(50000);
  while(T--){ scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    cout<<calc(b,d)-calc(b,c-1)-calc(a-1,d)+calc(a-1,c-1)<<endl; } }
【p2522】problem B //'ZAP'的一般情况:求∑(i=a~b)∑(j=c~d)[gcd(x,y)=k]

 

T3:【p2257】YY的GCD
  • 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x,y)为质数的(x,y)有多少对。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

//【p2257】YY的GCD
// 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对。

// ∑(i=1~n)∑(j=1~m)[gcd(x,y)=primes]

// 设f(d)为 gcd(i,j)=d 的个数,F(n)为 gcd(i,j)=d和d的倍数 的个数。
// 即:f(d)=∑(i=1~n)∑(j=1~m)[gcd(i,j)=d],F(n)=∑(n|d)f(d)=⌊N/n⌋⌊M/n⌋。
// 则可以得到:f(n)=∑(n|d) μ(⌊d/n⌋)*F(d)。

// 接下来的推导公式见:http://www.cnblogs.com/peng-ym/p/8652288.html

const int N=10000019;

bool vis[N]; int primes[N],cnt=0,mu[N],g[N]; ll sum[N];

void get_mu(int n){
    mu[1]=1; for(int i=2;i<=n;i++){
        if(!vis[i]) primes[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&primes[j]*i<=n;j++){
            vis[primes[j]*i]=1;
            if(i%primes[j]==0) break;
            else mu[i*primes[j]]=-mu[i];
        }
    } for(int j=1;j<=cnt;j++)
        for(int i=1;i*primes[j]<=n;i++) g[i*primes[j]]+=mu[i];
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(ll)g[i];
}

int main(){
    int T,n,m; cin>>T; get_mu(10000000);
    while(T--){
        scanf("%d%d",&n,&m); if(n>m) swap(n,m);
        ll ans=0; for(int l=1,r;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<<endl; //满足gcd(x,y)为质数的(x,y)对数
    }
}
【p2257】YY的GCD // 求 ∑(i=1~n)∑(j=1~m)[gcd(x,y)=primes] 

 

T4:【p3327】约数个数和
#include <cmath>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

//【p3327】约数个数和 // 设d(x)为x的约数个数,求 ∑(i=1~n)∑(j=1~m)d(i*j)

// 约数个数的公式:d(i*j)=∑(x|i)∑(y|j)[gcd(x,y)=1]。

// 设f(d)为 gcd(i,j)=d 的个数,F(n)为 gcd(i,j)=d和d的倍数 的个数。
// 即:f(d)=∑(i=1~n)∑(j=1~m)[gcd(i,j)=d],F(n)=∑(n|d)f(d)=⌊N/n⌋⌊M/n⌋。
// 则可以得到:f(n)=∑(n|d) μ(⌊d/n⌋)*F(d)。

// Ans=∑(i=1~n)∑(j=1~m)∑(x|i)∑(y|j)[gcd(x,y)=1]。
// 根据公式推出:Ans=∑(i=1~n)∑(j=1~m)∑(x|i)∑(y|j)∑(d|gcd(x,y))μ(d)。
// 后续推导见:https://www.cnblogs.com/peng-ym/p/8667321.html

const int N=10000019;

bool vis[N]; int primes[N],cnt=0,mu[N],g[N]; ll sum[N];

void get_mu(int n){
    mu[1]=1; for(int i=2;i<=n;i++){
        if(!vis[i]) primes[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&primes[j]*i<=n;j++)
         {  vis[primes[j]*i]=1;
            if(i%primes[j]==0) break;
            else mu[i*primes[j]]=-mu[i];  }
    } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
      for(int i=1;i<=n;i++){ 
        ll anss=0; for(int l=1,r;l<=i;l=r+1)
           r=(i/(i/l)),anss+=1LL*(r-l+1)*(i/l); g[i]=anss;
    }
}

int main(){
    int T,n,m; cin>>T; get_mu(50000);
    while(T--){ scanf("%d%d",&n,&m);
        ll ans=0; for(int l=1,r;l<=min(n,m);l=r+1){
            r=min(n/(n/l),m/(m/l)); //整除分块
            ans+=1LL*g[n/l]*1LL*g[m/l]*(sum[r]-sum[l-1]);
        } cout<<ans<<endl; //满足gcd(x,y)=d的(x,y)对数
    }
}
【p3327】约数个数和 // 设d(x)为x的约数个数,求 ∑(i=1~n)∑(j=1~m)d(i*j)。
  • 约数个数的公式:d(i*j)=∑(x|i)∑(y|j)[gcd(x,y)=1]

 

转载于:https://www.cnblogs.com/FloraLOVERyuuji/p/10539217.html

分数阶傅里叶变换(Fractional Fourier Transform, FRFT)是对传统傅里叶变换的拓展,它通过非整数阶的变换方式,能够更有效地处理非线性信号以及涉及时频局部化的问题。在信号处理领域,FRFT尤其适用于分析非平稳信号,例如在雷达、声纳和通信系统中,对线性调频(Linear Frequency Modulation, LFM)信号的分析具有显著优势。LFM信号是一种频率随时间线性变化的信号,因其具有宽频带和良好的时频分辨率,被广泛应用于雷达和通信系统。FRFT能够更精准地捕捉LFM信号的时间和频率信息,相比普通傅里叶变换,其性能更为出色。 MATLAB是一种强大的数值计算和科学计算工具,拥有丰富的函数库和用户友好的界面。在MATLAB中实现FRFT,通常需要编写自定义函数或利用信号处理工具箱中的相关函数。例如,一个名为“frft”的文件可能是用于执行分数阶傅里叶变换的MATLAB脚本或函数,并展示其在信号处理中的应用。FRFT的正确性验证通常通过对比变换前后信号的特性来完成,比如评估信号的重构质量、信噪比等。具体而言,可以通过计算原始信号经过FRFT处理后的信号之间的相似度,或者对比LFM信号的关键参数(如初始频率、扫频率和持续时间)是否在变换后得到准确恢复。 在MATLAB代码实现中,通常包含以下步骤:首先,生成LFM信号模型,设定其初始频率、扫频率、持续时间和采样率等参数;其次,利用自定义的frft函数对LFM信号进行分数阶傅里叶变换;接着,使用MATLAB的可视化工具(如plot或imagesc)展示原始信号的时域和频域表示,以及FRFT后的结果,以便直观对比;最后,通过计算均方误差、峰值信噪比等指标来评估FRFT的性能。深入理解FRFT的数学原理并结合MATLAB编程技巧,可以实现对LFM信号的有效分析和处理。这个代码示例不仅展示了理论知识在
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值