莫比乌斯反演&整数分块

前言

参考资料

  1. peng-ym-莫比乌斯反演

莫比乌斯反演

预备知识:整数分块(感觉就是一个思想)

  1. 参考博客:peng-ym-整除分块
    在这里插入图片描述

总结

  1. 一般形式 ∑ i = 1 n [ n / i ] \sum_{i=1}^{n}[n/i] i=1n[n/i]
  2. 过程:r=n/(n/l),然后不断枚举l,求得r,[l,r]部分的值是一样的,不必遍历,直接得到长度*数。
  3. 复杂度:由 O ( n ) O(n) O(n)变为 O ( n ) O(\sqrt{n}) O(n )

莫比乌斯函数 μ \mu μ(数论函数也可以视作一个数列)

在这里插入图片描述
在这里插入图片描述

总结

  1. 定义很重要
  2. 性质1很重要
  3. 性质2还需要回顾以下欧拉函数才行。

莫比乌斯反演

在这里插入图片描述
在这里插入图片描述

题目训练

题目1(oi-wiki推荐):求满足gcd(x,y)=k且x,y分别在区间[a,b],[c,d]内的个数(莫比乌斯反演&容斥定理&整数分块)

  1. 题目P2522 [HAOI2011]Problem b
    在这里插入图片描述
    在这里插入图片描述

  2. 题解

    1. 首先由容斥定理把题目简化为求四个 ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] \sum_{i=1}^{n} \sum_{j=1}^{m}[gcd(i,j)=1] i=1nj=1m[gcd(i,j)=1]的形式。
    2. 其中 [ g c d ( i , j ) = 1 ] [gcd(i,j)=1] [gcd(i,j)=1]表示满足内部条件时返回true,否则返回false。
    3. 莫比乌斯函数性质1 ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1]
    4. 带入得到: ∑ i = 1 n ∑ j = 1 m ∑ d ∣ g c d ( i , j ) μ ( d ) \sum_{i=1}^{n} \sum_{j=1}^{m}\sum_{d|gcd(i,j)}\mu(d) i=1nj=1mdgcd(i,j)μ(d)(即条件转化为具体求和式子)
    5. 变形得到: ∑ d = 1 m i n ( n , m ) ∑ i = 1 n [ d ∣ i ] ∑ j = 1 m [ d ∣ j ] \sum_{d=1}^{min(n,m)}\sum_{i=1}^n[d|i]\sum_{j=1}^{m}[d|j] d=1min(n,m)i=1n[di]j=1m[dj]
    6. 最后用整数分块解决以下就ok了(不过这里怎么就敢说复杂度为 O ( m a x ( n , m ) O(\sqrt{max(n,m}) O(max(n,m )呢?还是雀食不是根号,但是也大不了多少)。
  3. 代码

/*
4. 莫比乌斯反演
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
int a, b, c, d, k;
int mu[N], p[N], vis[N];

void Moblus(int n) {
    memset(vis, 0, sizeof(vis));
    mu[1] = 1;
    int tot = 0;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) p[tot++] = i, mu[i] = -1;
        for (int j = 0; j < tot; j++) {
            if (i * p[j] > n) break;
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) {
                mu[i * p[j]] = 0;
                break;
            } else
                mu[i * p[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= n; i++) mu[i] += mu[i - 1];
}
int solve(int n, int m) {
    int res = 0;
    for (int i = 1, j; i <= min(n, m); i = j + 1) {
        j = min(
            n / (n / i),
            m / (m / i));  // emmm,不敢多问,这你敢说是$O(\sqrt{n})$复杂度?
            // 得到一个正确的限制条件,然后模式化(无脑)枚举就好emm
        res += (mu[j] - mu[i - 1]) * (n / i) * (m / i);
    }
    return res;
}
//容斥定理
int f(int x, int k) {
    if (x % k == 0) return x / k - 1;
    return x / k;
}
signed main() {
    Moblus(N - 1);
    int T;
    cin >> T;
    while (T--) {
        scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
        int ans = solve(b / k, d / k) - solve(b / k, f(c, k)) -
                  solve(f(a, k), d / k) + solve(f(a, k), f(c, k));
        printf("%d\n", ans);
    }
    return 0;
}

题目2(cf2200):

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值