莫比乌斯反演

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;
}

以上是关于莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章

莫比乌斯反演

数论18——反演定理(莫比乌斯反演)

莫比乌斯反演

莫比乌斯反演总结

浅谈算法——莫比乌斯反演

bzoj 1101 Zap —— 莫比乌斯反演