码迷,mamicode.com
首页 > 其他好文 > 详细

莫比乌斯反演

时间:2020-01-14 13:24:55      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:分块   ++   前缀   tar   解法   spl   cal   getc   tps   

莫比乌斯函数

\[ \mu(i)=\left\{\begin{array}{c} {1 \ \ \ \ \ \ \ \ \ \ \ i=1} \hfill\{(-1)^{k}\ \ \ i=p 1 * p 2 * \ldots * p k} \{0\ \ \ \ \ \ \ \ \ \ \ 其他情况}\hfill \end{array}\right. \]

即不同质数的乘积,则为\((-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) g\left(\frac{n}{d}\right)\)

积性函数:对于任意互质的整数a和b有性质\(f(ab) = f(a) f(b)\)

完全积性函数:对于任意的整数a和b有性质\(f(ab) = f(a) f(b)\)

莫比乌斯函数\(\mu(i)\)和欧拉函数\(\varphi(i)\)都是积性函数

反演形式

\[ \begin{aligned}&约数形式\ \ F(n)=\sum_{d | n} f(d) \Longrightarrow f(n)=\sum_{d | n} u(d) F\left(\frac{n}{d}\right)\\&倍数形式\ \ F(n)=\sum_{n | d} f(d) \Longrightarrow f(n)=\sum_{n | d} u\left(\frac{d}{n}\right) F(d)\end{aligned} \]

对于一些\(f(n),如果容易求出倍数和或者约数和F(n),那么就可以通过反演求得f(n)的值\)

上面公式详细点就是

\(g(x)\)是给出的式子

进行构造函数\(f(n)\),反演出\(g(n)\)

约数形式\[\begin{aligned} &f(n)=\sum_{d | n} g(d)\&g(n)=\sum_{d | n} \mu(d) f\left(\frac{n}{d}\right) \end{aligned}\]

倍数形式\[\begin{aligned} &f(n)=\sum_{n | d} g(d)\&g(n)=\sum_{n | d} \mu\left(\frac{d}{n}\right) 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) + ... +g\left(\left\lfloor\frac{N}{d}\right\rfloor\right)\)

\(f(d) = \sum_{d|p}g(p)(p≤N)\)

进行反演

\(g(d)=\sum_{d | p} \mu\left(\frac{p}{d}\right) f(p)\)

因为\(\sum_{d|n}f(n)是指所有f(n)中满足d|n的个数 =\left\lfloor\frac{上限}{d}\right\rfloor\)

\(f(x) = \left\lfloor\frac{n}{x}\right\rfloor\left\lfloor\frac{m}{x}\right\rfloor\)

那么答案就是

\(g(d) = \sum_{d|p}\mu(\frac{p}{d})\left\lfloor\frac{n}{p}\right\rfloor\left\lfloor\frac{m}{p}\right\rfloor\)

枚举\(\left\lfloor\frac{p}{d}\right\rfloor = t\)

\(g(d) = \sum_{t = 1}^{min(n,m)}\mu(t)\left\lfloor\frac{n}{td}\right\rfloor\left\lfloor\frac{m}{td}\right\rfloor\)

然后整除分块一波即可

整除分块

\(\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor\)

普通的方法是\(O(n)\)

但是利用整除分块可以做到\(O(\sqrt{n})\)

因为有很多的\(\left\lfloor\frac{n}{i}\right\rfloor\)具有相同的值,每一个相同的值处于一块状分布

通过打表发现,一个分块的最后一个数是\(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\n",cal(b,d) - cal(b,c-1) - cal(a-1,d)+cal(a-1,c-1));
    }
    return 0;
}

莫比乌斯反演

标签:分块   ++   前缀   tar   解法   spl   cal   getc   tps   

原文地址:https://www.cnblogs.com/Emcikem/p/12191370.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!