洛谷P3455 [POI2007]ZAP-Queries 莫比乌斯反演+整除分块

洛谷P3455 [POI2007]ZAP-Queries

标签

  • 莫比乌斯反演

前言

  • 比较简单

简明题意

  • 给定\(n,m,d\),对于\(i<=n,j<=m\),问其中有多少对二元组\((i,j)\)使得\(gcd(i,j)==d\)
  • \(n,m<=5e4\)

思路

  • 首先用数学形式写出来,就是
    \[\sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)==d]\]
    根据我们的套路,是要将\([gcd(i,j)==d]\)的式子用\([gcd(i,j)==1]\)替换的,这样才能用莫比乌斯函数性质\(\sum_{d|n} \mu(d)=[n==1]\)从而降低复杂度。于是,我们换成\([gcd(i,j)==1]\)的形式:
    \[\sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]}[gcd(i,j)==1]\]
  • 接下来,我们就用\(\sum_{d|n} \mu(d)=[n==1]\)去替换条件式:
    \[\sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]}\sum_{d_0|gcd(i,j)} \mu(d_0)\]
  • 对于\(gcd\)有一个性质就是:\(d_0|gcd(i,j)\iff d_0|i 且 d_0|j\),于是原式就变成:
    \[\sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]}\sum_{d_0|i 且d_0|j} \mu(d_0)\]
  • 将原式改为枚举\(d_0\),根据\(d_0|i 且d_0|j\)可知\(d_0 \in [1,min(i,j)]\)\(d_0 \in [1,min([\frac nd],[\frac md])]\),所以原式:
    \[\sum_{d_0=1}^{min([\frac nd],[\frac md])]} \sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]} \left( \mu(d_0)*[d_0|i 且d_0|j] \right)\]
  • 我们又能惊奇的发现,\(\sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]}\)\(\mu(d_0)\)无关,所以可以把\(\mu(d_0)\)提到\(\sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac nd]}\)前面,于是就成了
    \[\sum_{d=1}^{min([\frac nd],[\frac md])]} \left( \mu(d_0) \sum_{i=1}^{[\frac nd]} \sum_{j=1}^{[\frac md]} [d_0|i 且d_0|j] \right)\]
  • 然后,其实 \(\sum \limits_{i=1}^{[\frac nd]} \sum \limits_{j=1}^{[\frac md]} [d_0|i 且d_0|j]\iff[\frac n{dd_0}]*[\frac m{dd_0}]\) (具体原因请自行举例琢磨),于是原式就成了:
    \[\sum_{d=1}^{min([\frac nd],[\frac md])]} \left( \mu(d_0)*[\frac n{dd_0}]*[\frac m{dd_0}] \right)\]
  • 来到了这里,是不是发现很容易就能整除分块了,因为每一块的\([\frac n{dd_0}]*[\frac m{dd_0}]\)是一样的,那就相当于是这一块的\(\mu d_0\)之和乘以这一块的\([\frac n{dd_0}]*[\frac m{dd_0}]\)。我们预处理出\(\mu(d_0)\)的前缀和,然后\(O(1)\)查询每一块\(\mu(d_0)\)的前缀和,每组样例的复杂度就是\(O(\sqrt n)\)

注意事项

  • 不开long long见祖宗~

总结

  • 我认为这一类题用到的仅仅是莫比乌斯函数的性质,要多做题才能有更深刻的理解

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 5e4 + 10;

bool no_prime[maxn];
int prime[maxn], mu[maxn], pre[maxn];
int shai(int n)
{
    int cnt = 0;
    mu[1] = 1;

    for (int i = 2; i <= n; i++)
    {
        if (!no_prime[i])
            prime[++cnt] = i, mu[i] = -1;

        for (int j = 1; j <= cnt && prime[j] * i <= n; j++)
        {
            no_prime[prime[j] * i] = 1;
            mu[prime[j] * i] = i % prime[j] == 0 ? 0 : -mu[i];
            if (i % prime[j] == 0) break;
        }
    }

    for (int i = 1; i <= n; i++)
        pre[i] = pre[i - 1] + mu[i];
    return cnt;
}

long long cal(int n, int m)
{
    long long ans = 0;
    int l = 1, r;
    while (l <= m)
    {
        r = min(n / (n / l), m / (m / l));
        ans += (long long)(pre[r] - pre[l - 1]) * (n / l) * (m / l);
        l = r + 1;
    }
    return ans;
}

void solve()
{
    shai(maxn - 10);

    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, m, d;
        scanf("%d%d%d", &n, &m, &d);
        if (n < m) swap(n, m);

        printf("%lld\n", cal(n / d, m / d));
    }
}

int main()
{
    solve();
    return 0;
}

转载于:https://www.cnblogs.com/danzh/p/11296686.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值