洛谷 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& ...
随机推荐
- vue基本指令与脚手架基本配置
脚手架(@vue/cli)创建项目启动服务 1.创建项目 vue create 项目名字 2.启动项目 进入项目根目录,运行以下命令 yarn serve 3.脚手架目录代码分析 ├── node_m ...
- TypeScript中将函数中的局部变量“导出”的方法
首先是在模块a.js中声明一个可导出(export)的数据结构,例如: export class ModelInfo{ id: string; name:string; } 其次是在模块b中声明可导出 ...
- 将DataFrame赋值为可变变量在spark中多次赋值后运行速度减慢的问题
该问题先标记上,之后有空了研究原因. 在var dataframe后将dataframe作为参数输入某方法,将结果重新赋予该dataframe,会导致spark运行显著减慢速度.暂时不知道原因,之后研 ...
- 爬虫逆向基础,理解 JavaScript 模块化编程 webpack
关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶.JS/安卓逆向等技术干货! 简介 在分析一些站点的 JavaScript 代码时,比较简单的代码,函数通常都是一个一个的,例 ...
- JBOSS未授权访问漏洞利用
1. 环境搭建 https://www.cnblogs.com/chengNo1/p/14297387.html 搭建好vulhub平台后 进入对应漏洞目录 cd vulhub/jboss/CVE-2 ...
- BUAA_2020_软件工程_热身作业
项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 热身作业要求 我在这个课程的目标 了解软件工程的技术,掌握工程化开发的能力 这个作业在哪个具体方面 ...
- VirtualBox Share Folder
转载:https://www.cnblogs.com/Dennis-mi/articles/5896586.html 使用virtualbox最方便的host-guest交换文件方案莫过于共享文件夹功 ...
- 2021CCPC河南省赛(部分代码待更)
最终A了8道题, 喜提一金, 也是在意料之中. 第一次三个队友集中在一起打比赛, 也体验了一下线下的氛围, 还是比较赞的, 自己也不是说毫无作用, 帮助团队做了几道题, 还是挺满意的. 1002 em ...
- Discovery直播 | 3D“模”术师,还原立体世界——探秘3D建模服务
通过多张普通的照片重建一个立体逼真的3D物体模型,曾经靠想象实现的事情,现在, 使用HMS Core 3D建模服务即可实现! 3D模型作为物品在数字世界中的孪生体,用户可以自己拍摄.建模并在终端直观感 ...
- C++ 默认拷贝构造函数 深度拷贝和浅拷贝
C++类默认拷贝构造函数的弊端 C++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数.它们的特殊之处在于: (1) 当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且 ...