zoukankan      html  css  js  c++  java
  • 莫比乌斯反演

    莫比乌斯函数

    [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;
    }
    
  • 相关阅读:
    Centos7 安装zabbix3.0 服务端 详细
    kubernetes 创建nginx 容器
    kubernetes 创建tomcat 容器
    kubernetes创建yaml,pod服务一直处于 ContainerCreating状态的原因查找与解决
    SpringMVC,SpringBoot利用ajax上传文件到后台
    SpringMVC,SpringBoot使用ajax传递对象集合/数组到后台
    IDEA修改显示星号*和热部署
    IDEA上的项目托管到码云步骤
    java代码块,静态代码块,静态变量,构造方法执行顺序
    java 动态绑定 多态
  • 原文地址:https://www.cnblogs.com/Emcikem/p/12191370.html
Copyright © 2011-2022 走看看