洛谷 P2257 - YY的GCD(莫比乌斯反演+整除分块)
题意:
- 求满足 \(1 \leq x \leq n\),\(1 \leq y \leq m\),\(\gcd(x,y)\) 为质数的数对 \((x,y)\) 的个数。
- \(T\) 组询问。
- \(1 \leq T \leq 10^4\),\(1 \leq n,m \leq 10^7\)。
今天终于学会了莫比乌斯反演反演~~,就写篇博客加深下印象吧。
要说这莫比乌斯反演有多么博大精深,就不得不从莫比乌斯函数 \(\mu(x)\) 说起。
我们定义 \(\mu(x)\) 为:
\]
当然,\(\mu(x)\) 有不少有趣的性质,其中最重要且最常用的一条是:
\]
为什么?其实很好理解。
当 \(x=1\) 时显然得证。
当 \(x \neq 1\) 时,设 \(n=\prod\limits_{i=1}^kp_i^{c_i},n'=\prod\limits_{i=1}^kp_i\)。
那么显然有 \(\sum\limits_{d|n}\mu(d)=\sum\limits_{d|n'}\mu(d)\)。
而 \(\sum\limits_{d|n'}\mu(d)=\sum\limits_{i=0}^k\dbinom{k}{i}\times (-1)^i\)。
由二项式定理易得原式 \(=0\)。故原命题成立。
那这形式诡异的莫比乌斯函数对我们解题能有什么帮助呢?
这就要引入一个更加神的知识:莫比乌斯反演。
何谓反演?相信不少刚学莫比乌斯反演的人都会有这样的疑问。
回忆起圆的反演。如果存在圆 \(O\) 与点 \(P\) 与 \(P'\) 使得 \(O,P,P'\) 共线且 \(|OP| \times |OP'|=r^2\),那么就称“\(P\) 与 \(P'\) 互为圆 \(O\) 的反演点”。知道了 \(P\) 的位置,\(P'\) 的位置也确定下来了。反之亦然。
莫比乌斯反演也类似。假设我们有两个函数 \(f(n),F(n)\),满足 \(F(n)=\sum\limits_{d|n}f(d)\),那么 \(f(n)=\sum\limits_{d|n}\mu(d)F(\dfrac{n}{d})\)。
怎么证明这个定理呢?最简单的方法是利用狄利克雷卷积来证明。可惜我不会, 5 天后咱再回头来看用狄利克雷卷积的解法。这里介绍一种纯推式子的方法:
\]
同时,还有第二种形式的莫比乌斯反演。如果 \(F(n)=\sum\limits_{n|d}f(n)\),那么 \(f(n)=\sum\limits_{n|d}\mu(\frac{d}{n})F(d)\)。证明方法与第一种形式的莫比乌斯反演几乎一样,这里就不再赘述了。
说了这么多,相信大家对莫比乌斯反演有了一定的了解。那么莫比乌斯函数及莫比乌斯反演怎样真正应用在题目中呢?我们就以这道题为例来看一看。
很自然地想到枚举 \(\gcd\),即 \(\sum\limits_{p \in prime}\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=p]\)。
下面就是套路了。令 \(f(d)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=d]\),\(F(d)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[d|\gcd(i,j)]\)。
显然 \(F(p)=\sum\limits_{p|d}f(d)\)。
套用第二种形式的莫比乌斯反演得 \(f(p)=\sum\limits_{p|d}\mu(\frac{d}{p})F(d)\)。
这样转化有什么好处呢?不难发现要求 \(f(d)\) 非常棘手,但是要求 \(F(d)\) 非常容易————\(F(d)=\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor\)
一不做二不休,把 \(F(d)\) 带回原式得 \(f(p)=\sum\limits_{p|d}\mu(\frac{d}{p})\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor\)
最后计算答案。\(ans=\sum\limits_{p \in prime}f(p)=\sum\limits_{p \in prime}\sum\limits_{p|d}\mu(\frac{d}{p})\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor=\sum\limits_{d=1}^n\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor\sum\limits_{p|d \operatorname{and} p \in prime}\mu(\frac{d}{p})\)
记 \(t_d=\sum\limits_{p|d \operatorname{and} p \in prime}\mu(\frac{d}{p})\),显然可以在 \(\mathcal O(n \log n)\) 的时间复杂度内求出所有 \(t_d\)。还是把 \(t_d\) 带回去,\(ans=\sum\limits_{d=1}^n\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor t_d\)。
如果单次询问那么的确一遍循环就可以了。可是本题有 \(10^4\) 组数据,出题人显然不会放过 \(\mathcal O(nT)\) 解法。如何进行优化呢?
考虑一个特别经典的问题,求 \(\sum\limits_{i=1}^n\lfloor \frac{n}{i} \rfloor\)。
显然,暴力的 \(\mathcal O(n)\) 的解法是不能被接受的。
不过仔细观察就会发现一个性质:有不少重复的 \(\lfloor \frac{n}{i} \rfloor\),而且 \(\lfloor \frac{n}{i} \rfloor\) 相同的 \(i\) 是成段分部的。
故我们可以找出 \(\lfloor \frac{n}{i} \rfloor\) 相同的段然后计算贡献。最多有 \(2 \sqrt{n}\) 个这样的段。
这就是著名的整除分块的思想。
回到本题来。使用类似的套路,找出 \(\lfloor \frac{n}{i} \rfloor\) 与 \(\lfloor \frac{m}{i} \rfloor\) 都相同的 \(i\)——它们也一定是成段分部的,使用前缀和计算贡献就完事了。
时间复杂度 \(\mathcal O(T\sqrt{n}+n \log n)\)。
/*
Contest: -
Problem: P2257
Author: tzc_wk
Time: 2020.8.31
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
int T=read();
bool vis[10000005];
ll mu[10000005],pri[5000005],sum[10000005],t[10000005],pcnt=0;
inline void get_mu(){
mu[1]=1;
for(int i=2;i<=10000000;i++){
if(!vis[i]){mu[i]=-1;pri[++pcnt]=i;}
for(int j=1;j<=pcnt&&pri[j]*i<=10000000;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
else mu[pri[j]*i]=-mu[i];
}
}
for(int i=1;i<=pcnt;i++) for(int j=1;j*pri[i]<=10000000;j++) t[j*pri[i]]+=mu[j];
for(int i=1;i<=10000000;i++) sum[i]=sum[i-1]+t[i];
}
int main(){
get_mu();
while(T--){
int n=read(),m=read();
ll ans=0;
for(int l=1,r;l<=min(n,m);l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}
洛谷 P2257 - YY的GCD(莫比乌斯反演+整除分块)的更多相关文章
- 洛谷 - P2257 - YY的GCD - 莫比乌斯反演 - 整除分块
https://www.luogu.org/problemnew/show/P2257 求 \(n,m\) 中 \(gcd(i,j)==p\) 的数对的个数 求 $\sum\limits_p \sum ...
- 洛谷P2257 YY的GCD 莫比乌斯反演
原题链接 差不多算自己推出来的第一道题QwQ 题目大意 \(T\)组询问,每次问你\(1\leqslant x\leqslant N\),\(1\leqslant y\leqslant M\)中有多少 ...
- 洛谷 P2257 YY的GCD
洛谷 P2257 YY的GCD \(solution:\) 这道题完全跟[POI2007]ZAP-Queries (莫比乌斯反演+整除分块) 用的一个套路. 我们可以列出答案就是要我们求: \(ans ...
- [BZOJ 2820] YY的gcd(莫比乌斯反演+数论分块)
[BZOJ 2820] YY的gcd(莫比乌斯反演+数论分块) 题面 给定N, M,求\(1\leq x\leq N, 1\leq y\leq M\)且gcd(x, y)为质数的(x, y)有多少对. ...
- 洛谷P2257 YY的GCD(莫比乌斯反演)
传送门 原来……莫比乌斯反演是这么用的啊……(虽然仍然不是很明白) 首先,题目所求如下$$\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=prim]$$ 我们设$f(d)$表示$g ...
- 洛谷 P2257 YY的GCD 题解
原题链接 庆祝: 数论紫题 \(T4\) 达成! 莫比乌斯 \(T1\) 达成! yy 真是个 神犇 前记 之前我觉得: 推式子,直接欧拉筛,筛出个 \(\phi\),然后乱推 \(\gcd\) 就行 ...
- 洛谷P2257 YY的GCD
今日份是数论 大概是..从小学奥数到渐渐毒瘤 那就简单列一下目录[大雾 同余 质数密度 唯一分解定理 互质 完全剩余系 简化剩余系 欧拉函数 逆元 斐蜀定理 阶(及其性质) 欧拉定理 费马小定理 原根 ...
- Luogu P2257 YY的GCD 莫比乌斯反演
第一道莫比乌斯反演...$qwq$ 设$f(d)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]$ $F(n)=\sum_{n|d}f(d)=\lfloor \frac{N ...
- Bzoj 2820: YY的GCD(莫比乌斯反演+除法分块)
2820: YY的GCD Time Limit: 10 Sec Memory Limit: 512 MB Description 神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x& ...
随机推荐
- 【实验向】问题:假设计算机A和计算机B通信,计算机A给计算机B发送一串16个字节的二进制字节串,以数组形式表示:
问题: 假设计算机A和计算机B通信,计算机A给计算机B发送一串16个字节的二进制字节串,以数组形式表示: unsigned char[16] = {0x3f, 0xa0, 0x00, 0x00, 0x ...
- WPF中的命令(Command)
这节来讲一下WPF中的命令(Command)的使用. [认识Command] 我们之前说过,WPF本身就为我们提供了一个基础的MVVM框架,本节要讲的命令就是其中一环,通过在ViewModel中声明命 ...
- Beta Scrum Meeting汇总
第0次Alpha Scrum Meeting 第1次Alpha Scrum Meeting 第2次Alpha Scrum Meeting 第3次Alpha Scrum Meeting 第4次Alpha ...
- 使用Keil下载Hex文件进STM32
前言 初学STM32时,是通过串口1把Hex文件下载进STM32的,需要一个串口模块,而且还要设置BOOT0和BOOT1电平,然后通过FlyMcu软件进行下载,这也是一种不错的方法,这里我要介绍的是使 ...
- stm32f103系列引脚定义-功能图
器件功能和配置(STM32F103xx增强型) STM32F103xx增强型模块框架图 STM32F103xx增强型VFQFPN36管脚图 STM32F103xx增强型LQFP100管脚图 STM32 ...
- 单片机STM32学习笔记之寄存器映射详解
我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫寄存器映射?寄存器到底是什么? 在存储器Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共32bit,每一 ...
- 云效Flow如何实现阿里云ECS多环境发布
一.背景 云效Flow基于标签功能实现阿里云ECS多环境发布,在软件开发和部署过程中,我们的软件往往需要在不同的运行环境中运行,例如:开发人员本地开发环境.测试团队的测试环境.还有类生产环境和生产环境 ...
- hdu 5093 Battle ships(二分图最大匹配)
题意: M*N的矩阵,每个格子上是三个之一:*.o.#. (1 <= m, n <= 50) *:海洋,战船可以停在上面. o:浮冰,战船 ...
- 西邮Linux兴趣小组第一次技术分享会
2016年10月30日晚,西邮Linux兴趣小组技术分享会在西安邮电大学长安校区东区逸夫教学楼FF305室成功举办.200多名来自全校不同专业的15,16级同学参加了此次分享会. 分享会于20:00正 ...
- split,cdn,shell脚本,tmux,记一次往国外服务器传大文件的经历
需求是这样的:将一个大概680M的Matlab数据文件传到国外某所大学的服务器上,服务器需要连接VPN才能访问,由于数据文件太大,而且如果我直接ssh连过去或者用ftp传输,那么中间很可能中断. ps ...