215. 破译密码

题目链接

215. 破译密码

达达正在破解一段密码,他需要回答很多类似的问题:

对于给定的整数 a,bd,有多少正整数对 x,y,满足 xayb,并且 gcd(x,y)=d

作为达达的同学,达达希望得到你的帮助。

输入格式

第一行包含一个正整数 n,表示一共有 n 组询问。

接下来 n 行,每行表示一个询问,每行三个正整数,分别为 a,b,d

输出格式

对于每组询问,输出一个正整数,表示满足条件的整数对数。

数据范围

1n50000,
1da,b50000

输入样例:

2 4 5 2 6 4 3

输出样例:

3 2

提示:gcd(x,y) 返回 xy 的最大公约数。

解题思路

容斥原理,莫比乌斯函数

莫比乌斯函数:mobius[i]mobius[i],对 i 分解质因数,若 i 某一项质因子个数大于 1,则 mobius[i]=0,如果质因子种数为奇数则 mobius[i]=1,否则 mobius[i]=1理解:对于 n 的欧拉函数,由容斥原理,得 ϕ(n)=ns2s3+s2,3+s3,5+s2,3,5+,其中 sa1,a2,am 表示与 n 的公因子为 a1,a2,am 的个数,其系数正好为莫比乌斯函数

由于 gcd(x,y)=d,即 gcd(x/d,y/d)=1,问题转换为满足 x[1,a/d],y[1,b/d]gcd(x,y)=1 的对数,由容斥原理,答案即为 (a/d)×(b/d)s2s3+s6+,令 a=a/d,b=b/d,答案即为 a×b(a/2)×(b/2)(a/3)×(b/3)+(a/6)×(b/6)+,令 n=min(a,b),即为 i=1n(a/i)×(b/i)×mobius[i],其中 a/i 共有 O(a) 种取值,简略说下,将 a 分成两段:[1,a],[a,a]a/i 分成的两段的值的范围都为 O(a)
另外还有如下定理:
对于 a/x 该段取值的最大的一个 xg(x)=a/(a/x)a,b 表示的段都是 O() 级别,每次跳到 a,b 表示的段的较小边界即可

  • 时间复杂度:O(nn)

代码

// Problem: 破译密码 // Contest: AcWing // URL: https://www.acwing.com/problem/content/217/ // Memory Limit: 64 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5; LL res; int prime[N],u[N],s[N],v[N],m; void primes(int n) { u[1]=1; for(int i=2;i<=n;i++) { if(v[i]==0) { u[i]=-1; v[i]=prime[++m]=i; } for(int j=1;prime[j]*i<=n&&j<=m;j++) { if(v[i]<prime[j])break; if(i%prime[j]==0) u[i*prime[j]]=0; else u[i*prime[j]]=-u[i]; v[i*prime[j]]=prime[j]; } } for(int i=1;i<=n;i++)s[i]=s[i-1]+u[i]; } int g(int a,int b) { return a/(a/b); } int main() { primes(N-1); int t; cin>>t; while(t--) { int a,b,d; cin>>a>>b>>d; a/=d,b/=d; int n=min(a,b); res=0; for(int l=1,r;l<=n;l=r+1) { r=min(g(a,l),g(b,l)); res+=1ll*(s[r]-s[l-1])*(a/l)*(b/l); } cout<<res<<'\n'; } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16421170.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示