博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷 P2257 YY的GCD
阅读量:4654 次
发布时间:2019-06-09

本文共 2182 字,大约阅读时间需要 7 分钟。

ESYe9x.png



\(solution:\)

这道题完全跟 用的一个套路。

我们可以列出答案就是要我们求:

\(ans=\sum_{p\in prime}\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==p]}}\)

我们发现后面那一部分(\(\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==p]}}\))可以套路的莫比乌斯反演:

\(ans=\sum_{p\in prime}\sum_{i=1}^{\frac{n}{p}}{\sum_{j=1}^{\frac{m}{p}}{[gcd(i,j)==1]}}\)

\(ans=\sum_{p\in prime}\sum_{i=1}^{\frac{n}{p}}{\sum_{j=1}^{\frac{m}{p}}{\sum_{k|gcd(i,j)}{\mu(k)}}}\)

\(ans=\sum_{p\in prime}\sum_{k}^{min(n,m)}{\mu(k)}{\sum_{i=1}^{\frac{n}{p}}{\sum_{j=1}^{\frac{m}{p}}{[k|gcd(i,j)]}}}\)

\(ans=\sum_{p\in prime}\sum_{k}^{min(n,m)}{\mu(k)\times \lfloor \frac{n}{p\times k} \rfloor \times \lfloor \frac{m}{p\times k} \rfloor}\)

我们发现后面那两个东西有点麻烦,我们想办法让它变成常数项:

设: \(T=p\times k\)

\(ans=\sum_{t=1}^{min(n,m)} \lfloor \frac{n}{T} \rfloor \times \lfloor \frac{m}{T} \rfloor \sum_{p|T,p\in prime} \mu{\frac{T}{p}}\)

然后我们发现后面那一部分(\(\sum_{p|T,p\in prime} \mu{\frac{T}{p}}\))可以预处理,然后我们在前面用整除分块,这样就可以每次只用\(log(min(n,m))\)的时间完成单个询问了!



\(code:\)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long#define db double#define inf 0x7fffffff#define rg register intusing namespace std;const int N=1e7;ll ans;int n,m,t;int pr[10000005];int mu[10000005];int sum[10000005];bool zhi[10000005];inline int qr(){ register char ch; register bool sign=0; rg res=0; while(!isdigit(ch=getchar())) if(ch=='-')sign=1; while(isdigit(ch)) res=res*10+(ch^48),ch=getchar(); return sign?-res:res;}inline void get_ready(){ mu[1]=1; int t=0; for(rg i=2;i<=N;++i){ if(!zhi[i])pr[++t]=i,mu[i]=-1; for(rg j=1;j<=t;++j){ if(i*pr[j]>N)break; zhi[i*pr[j]]=1; if(!(i%pr[j]))break; mu[i*pr[j]]=-mu[i]; } } for(rg i=1;i<=t;++i) for(rg j=1;j*pr[i]<=N;++j) sum[j*pr[i]]+=mu[j]; for(rg i=1;i<=N;++i) sum[i]+=sum[i-1];}int main(){ //freopen(".in","r",stdin); //freopen(".out","w",stdout); t=qr(); get_ready(); while(t--){ ans=0; n=qr(); m=qr(); rg x=min(n,m),l,r; for(l=1;l<=x;l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=(ll)(n/l)*(m/l)*(sum[r]-sum[l-1]); }printf("%lld\n",ans); } return 0;}

转载于:https://www.cnblogs.com/812-xiao-wen/p/10729156.html

你可能感兴趣的文章
python sys.argv[] 用法示例
查看>>
Vcl.FileCtrl.SelectDirectory
查看>>
Java实现导入Excel文件
查看>>
动态执行超过4000个字符的SQL
查看>>
redhat 6.0更换 yum
查看>>
windows phone (27) 基础Button
查看>>
Java 判断是否为回文字符串
查看>>
(安全)工厂方法模式
查看>>
Hdu【线段树】基础题.cpp
查看>>
SQLITE入门-逐步讲解SQLITE命令行(六)
查看>>
Combine String HDU - 5707 dp or 广搜
查看>>
VB6.0 API 累计
查看>>
第十周学习进度博客
查看>>
Ecshop 最小起订量如何设置
查看>>
不使用其他变量实现两变量互换
查看>>
bcp功能
查看>>
xcode项目打不开:incompatible project version问题
查看>>
学习网站
查看>>
C#4.0新特性dynamic\可选参数、命名参数
查看>>
使用免费SSL证书让网站支持HTTPS访问
查看>>