假设我们手头有个数列 F,通过某种变换 H,可以得到函数 G。,即:
但现在只有函数 G,需要求 F,那么我们就需要寻找一种变换 ,使得 G 在经过这种变换后能够获得 F,这个过程即为反演,即:
对于式子:,其时间复杂度为 O(n),当有多组数据时,O(n) 并非正确的时间复杂度,此时有一种时间复杂度为 O(√n) 的算法:整除分块
对于每一个 通过打表发现,很多 的值是相同的,它们呈一个块状分布,对每一个值相同的块,它的最后一个数是:
有时候,可能式子不一定是一个裸的整除分块,可能会与某些积性函数相乘,这时就需要对这些函数统计一个前缀和。因为,每当我们使用整除分块跳过一个区间的时候,其所对应的函数值也跳过了一个区间,所以就需要乘上那一个区间的函数值
实现
int res=0;
for(int left=1,right;left<=n;left=right+1){
right=n/(n/left);
res+=(righr-left+1)*(n/left);
}
对于式子:,其时间复杂度为 O(n^2),同样可以使用整除分块的做法来降低时间复杂度
int res=0;
int minn=min(n,m);
for(int left=1,right;left<=minn;left=right+1){
right=min(n/(n/left),m/(m/left));
res+=(righr-left+1)*(n/left)*(m/left);
}
其中对于 的情况,,且 均为互质素数
简单来说,其满足以下几点:
int mu[N];
void getMu(){
for(int i=1;i
int mu[N];
int prime[N];
bool bprime[N];
int cnt;
void getMu(int n){//线性筛求莫比乌斯函数
cnt=0;
mu[1]=1;//根据定义,μ(1)=1
memset(bprime,false,sizeof(bprime));
for(int i=2;i<=n;i++){//求2~n的莫比乌斯函数
if(!bprime[i]){
prime[++cnt]=i;//存储质数
mu[i]=-1;//i为质数时,μ(1)=-1
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){//枚举i之前的素数个数
bprime[i*prime[j]]=true;//不是质数
if(i%prime[j])//i不是prime[j]的整数倍时,i*prime[j]就不会包含相同质因子
mu[i*prime[j]]=-mu[i];//mu[k]=mu[i]*mu[prime[j]],因为prime[j]是质数,mu值为-1
else{
mu[i*prime[j]]=0;
break;//留到后面再筛
}
}
}
}
对于一些函数f(n),很难直接求出其值,但容易求出约数和或倍数和g(n),那么可以通过莫比乌斯反演来求得f(n)
莫比乌斯反演的题目通常能转化为(x,y)=1的计数问题,即用f(n)表示某一范围(x,y)=n的数对数量,g(n)表示某一范围内n|(x,y)的数对数量。
和 是定义在非负整数集合上的两个函数,那么有: