莫比乌斯反演
Posted emcikem
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了莫比乌斯反演相关的知识,希望对你有一定的参考价值。
莫比乌斯函数
[ mu(i)=left{egin{array}{c} {1 i=1} hfill{(-1)^{k} i=p 1 * p 2 * ldots * p k} {0 其他情况}hfill end{array} ight. ]
即不同质数的乘积,则为((-1)^{k}) ,(mu(1) = 1),其他情况为0
线性筛莫比乌斯函数
int pri[maxn];
int tot = 0;
int mu[maxn];
bool vis[maxn];
void mu_table(int N){//莫比乌斯函数
mu[1] = 1;//i = 1
for(int i = 2; i <= N; i++){
if(!vis[i]){
pri[++tot] = i;
mu[i] = -1;//第二种情况
}
for(int j = 1; j <= tot; j++){
if(i * pri[j] > N)break;
vis[i * pri[j]] = 1;
if(i % pri[j] == 0){
mu[i * pri[j]] = 0;//第三种情况
break;
}else mu[i * pri[j]] = - mu[i];//第二种情况
}
}
}
狄利克雷卷积
((f * g)(n)=sum_{d | n} f(d) gleft(frac{n}{d} ight))
积性函数:对于任意互质的整数a和b有性质(f(ab) = f(a) f(b))
完全积性函数:对于任意的整数a和b有性质(f(ab) = f(a) f(b))
莫比乌斯函数(mu(i))和欧拉函数(varphi(i))都是积性函数
反演形式
[ egin{aligned}&约数形式 F(n)=sum_{d | n} f(d) Longrightarrow f(n)=sum_{d | n} u(d) Fleft(frac{n}{d} ight)\&倍数形式 F(n)=sum_{n | d} f(d) Longrightarrow f(n)=sum_{n | d} uleft(frac{d}{n} ight) F(d)end{aligned} ]
对于一些(f(n),如果容易求出倍数和或者约数和F(n),那么就可以通过反演求得f(n)的值)
上面公式详细点就是
(g(x))是给出的式子
进行构造函数(f(n)),反演出(g(n))
约数形式[egin{aligned} &f(n)=sum_{d | n} g(d)&g(n)=sum_{d | n} mu(d) fleft(frac{n}{d} ight) end{aligned}]
倍数形式[egin{aligned} &f(n)=sum_{n | d} g(d)&g(n)=sum_{n | d} muleft(frac{d}{n} ight) f(d) end{aligned}]
举例子:
给出一个式子(g(x)=sum_{i=1}^{n} sum_{j=1}^{m}[g c d(i, j)==d])
用第二组式子构造(f(x) = g(d) + g(2d) + ... +gleft(leftlfloorfrac{N}{d} ight floor ight))
即(f(d) = sum_{d|p}g(p)(p≤N))
进行反演
(g(d)=sum_{d | p} muleft(frac{p}{d} ight) f(p))
因为(sum_{d|n}f(n)是指所有f(n)中满足d|n的个数 =leftlfloorfrac{上限}{d} ight floor)
(f(x) = leftlfloorfrac{n}{x} ight floorleftlfloorfrac{m}{x} ight floor)
那么答案就是
(g(d) = sum_{d|p}mu(frac{p}{d})leftlfloorfrac{n}{p} ight floorleftlfloorfrac{m}{p} ight floor)
枚举(leftlfloorfrac{p}{d} ight floor = t)
(g(d) = sum_{t = 1}^{min(n,m)}mu(t)leftlfloorfrac{n}{td} ight floorleftlfloorfrac{m}{td} ight floor)
然后整除分块一波即可
整除分块
(sum_{i=1}^{n}leftlfloorfrac{n}{i} ight floor)
普通的方法是(O(n))
但是利用整除分块可以做到(O(sqrt{n}))
因为有很多的(leftlfloorfrac{n}{i} ight floor)具有相同的值,每一个相同的值处于一块状分布
通过打表发现,一个分块的最后一个数是(n/(n/i))所以可以用(sqrt{n})
for(int l = 1,r; l <= n; l = r + 1){
r = n/(n/l);
ans += (r - l + 1) * (n/l);//这一段的值相同
}
题
上面的那个式子的解法
传送门
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn = 5e4 + 5;
int tot = 0;
int mu[maxn];
bool vis[maxn];
int pri[maxn];
int sum[maxn];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
void mu_table(int N){
mu[1] = 1;
for(int i = 2; i <= N; i++){
if(!vis[i]){
pri[++tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot; j++){
if(i * pri[j] > N)break;
vis[i * pri[j]] = 1;
if(i % pri[j] == 0){
mu[i * pri[j]] = 0;
break;
}else mu[i * pri[j]] = -mu[i];
}
}
for(int i = 1; i <= N; i++)sum[i] = sum[i - 1] + mu[i];//此处前缀和是为了整除分块
}
int k;
int cal(int a,int b){
int ans = 0;
int mx = a/k;
int my = b/k;
int minn = min(mx,my);
for(int l = 1,r; l <= minn; l = r + 1){
r = min(mx/(mx/l),my/(my/l));
ans += (mx/l) * (my/l) * (sum[r] - sum[l - 1]);
}
return ans;
}
int main(){
int t;
mu_table(50000);
t = read();
while(t--){
int a,b,c,d;
a = read(),b = read(), c = read(),d = read();
k = read();
printf("%d
",cal(b,d) - cal(b,c-1) - cal(a-1,d)+cal(a-1,c-1));
}
return 0;
}
以上是关于莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章