莫比乌斯反演 / 数论分块 / 莫比乌斯函数模板 / P2522


前言

本文给出莫比乌斯函数的模板以及数论分块的操作
莫比乌斯反演的作用是将一些不方便计算的数论函数转变为好计算的函数(特指莫比乌斯函数和欧拉函数),
反演的本质也就是狄利克雷卷积的使用,其满足交换律、结合律、分配律
且 单位元 为 ϵ \epsilon ϵ ,若 f f f g g g为积性函数,则 f ∗ g f*g fg也为积性函数
μ ∗ 1 = ϵ \mu * 1 = \epsilon μ1=ϵ ϕ ∗ 1 = i d \phi * 1 = id ϕ1=id 1 ∗ 1 = d 1 * 1=d 11=d i d ∗ 1 = σ id*1=\sigma id1=σ f ∗ ϵ = f f * \epsilon = f fϵ=f 莫比乌斯反演: f = g ∗ 1    ⟹    g = f ∗ μ f = g * 1 \implies g = f * \mu f=g1g=fμ一个有用的定理: d ( m n ) = ∑ i ∣ m ∑ j ∣ n [ g c d ( i , j ) = 1 ] d(mn)=\sum_{i|m}\sum_{j|n}[gcd(i,j)=1] d(mn)=imjn[gcd(i,j)=1]

一、例题

很好的入门题 洛谷P2522

二、思路及代码

1.思路

问题可以进行区间转化,进而只需求以下和式: ∑ i = 1 m ∑ j = 1 n [ g c d ( i , j ) = k ] \sum_{i=1}^{m} \sum_{j=1}^{n}[gcd(i, j)=k] i=1mj=1n[gcd(i,j)=k]我们对其稍加变换,进而只需求: ∑ i = 1 ⌊ m k ⌋ ∑ j = 1 ⌊ n k ⌋ [ g c d ( i , j ) = 1 ] \sum_{i=1}^{ \lfloor \frac{m}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{k} \rfloor}[gcd(i, j)=1] i=1kmj=1kn[gcd(i,j)=1]接下来开始莫比乌斯反演 ∑ i = 1 ⌊ m k ⌋ ∑ j = 1 ⌊ n k ⌋ [ g c d ( i , j ) = 1 ] = ∑ i = 1 ⌊ m k ⌋ ∑ j = 1 ⌊ n k ⌋ ϵ ( g c d ( i , j ) ) = ∑ i = 1 ⌊ m k ⌋ ∑ j = 1 ⌊ n k ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ d ≥ 1 ⌊ m k d ⌋ n k d ⌋ μ ( d ) \sum_{i=1}^{ \lfloor \frac{m}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{k} \rfloor}[gcd(i, j)=1] \\ =\sum_{i=1}^{ \lfloor \frac{m}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{k} \rfloor} \epsilon(gcd(i, j)) \\= \sum_{i=1}^{ \lfloor \frac{m}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{k} \rfloor} \sum_{d|gcd(i, j)} \mu(d) \\ =\sum_{d \ge1}\lfloor \frac{m}{kd} \rfloor\frac{n}{kd} \rfloor \mu(d) i=1kmj=1kn[gcd(i,j)=1]=i=1kmj=1knϵ(gcd(i,j))=i=1kmj=1kndgcd(i,j)μ(d)=d1kdmkdnμ(d)
至此,式子就推完了,可以利用数论分块进行求和

2.代码

代码如下:

#include <iostream>
#define int long long
using namespace std;
const int maxn = 5e4 + 4;
int miu[maxn], premiu[maxn];
int prime[maxn], pn;
bool isp[maxn];
void miu_table() {
  for (int i = 1; i < maxn; i++) isp[i] = true;
  miu[1] = 1, isp[1] = false;
  for (int i = 2; i < maxn; i++) {
    if (isp[i]) prime[pn++] = i, miu[i] = -1;
    for (int j = 0; j < pn && i * prime[j] < maxn; j++) {
      isp[i * prime[j]] = 0;
      if (i % prime[j] == 0) {
        miu[i * prime[j]] = 0;
        break;
      }
      miu[i * prime[j]] = -miu[i];
    }
  }
  for (int i = 1; i < maxn; i++) premiu[i] = miu[i] + premiu[i - 1];
}
int solve(int n, int m) {
  int ans = 0;  // 二维分块
  for (int l = 1, r; l <= min(n, m); l = r + 1) {
    r = min(n / (n / l), m / (m / l));  // [l, r]内(n / i) * (m / i)值一样
    ans += (premiu[r] - premiu[l - 1]) * (n / l) * (m / l);
  }
  return ans;
}
signed main() {
  //   freopen("in.txt", "r", stdin);
  //   freopen("out.txt", "w", stdout);
  int t;
  scanf("%lld", &t);
  miu_table();
  while (t--) {
    int a, b, c, d, k;
    scanf("%lld%lld%lld%lld%lld", &a, &b, &c, &d, &k);
    int ans = solve(b / k, d / k) - solve((a - 1) / k, d / k) -
              solve(b / k, (c - 1) / k) + solve((a - 1) / k, (c - 1) / k);
    printf("%lld\n", ans);
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值