2024-03-27
2024-03-27
GCD
= 题目描述 =
给定正整数 \(n\),求 \(1\le x,y\le n\) 且 \(\gcd(x,y)\) 为素数的数对 \((x,y)\) 有多少对
= Solution =
\[\begin{align*}
ans&=\sum_{p\in primes}\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=p] \newline
&=\sum_{p\in primes}\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{n}{p}\right\rfloor}[\gcd(i,j)=1]
\end{align*}
\]
这个转挺常见的,要记住
继续转化
现在的 \(i,j\) 是没有顺序的
我们给他规定一个顺序,将 \(j\) 限制在 \([1,i]\)
所有 \(j>i\) 的情况都唯一对应了一种 \(j<i\) 的情况(i, j 交换即可)
所以规定顺序之后的答案要 ×2
发现 所有的 \(i=j\) 的情况都被重复计算了
但是只有 \(i=j=1\) 的时候会对答案贡献 \(1\)
把多出来的 1 减掉就行了
\[\therefore ans=\sum_{p\in primes}\left(2\times\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\left(\sum_{j=1}^i[\gcd(i,j)=1]\right)-1\right)\newline
\]
发现最里层括号套着的和式其实就是 \(\varphi(i)\)
\[ans=\sum_{p\in primes}\left(2\times\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\varphi(i)-1\right)
\]
线性筛求出素数和欧拉函数
欧拉函数做个前缀和
时间复杂度 \(O(n)\)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e7+100;
int primes[N],cntp;
bool st[N];
ll phi[N];
void init_p(int mx) {
phi[1]=1;
for(int i=2;i<=mx;i++) {
if(!st[i]) primes[++cntp]=i,phi[i]=i-1;
for(int j=1;i*primes[j]<=mx;j++) {
st[i*primes[j]]=true;
if(i%primes[j]==0) {
phi[i*primes[j]]=phi[i]*primes[j]*1;
break;
}
phi[i*primes[j]]=phi[i]*(primes[j]-1);
}
}
for(int i=1;i<=mx;i++) phi[i]+=phi[i-1];
}
int n;
int main() {
scanf("%d",&n);
init_p(n);
ll ans=0;
for(int j=1;j<=cntp;j++) ans+=(2*phi[n/primes[j]]-1);
printf("%lld\n",ans);
return 0;
}
YY的GCD
刚才那题的升级版
\(i\in[1,n],j\in[1,m] \ \ \ m,n\le10^7\),\(T\le10^4\) 组询问,求 \(\gcd(i,j)\) 是素数的 \((i,j)\) 对数
没做完
中间去给同学讲了一下上回考试的题
感觉这次语言组织能力就好多了