Luogu P2257 YY的GCD
gate
一年多前做的题,没想到当时还是会莫反的,果然现在越来越菜了
求:
\[\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)\in prime]
\]
设\(gcd(i,j)=k,n>m\)(否则swap)
\[\sum\limits_{k=1}^n\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)=k](k\in prime)
\]
同时除以\(k\)
\[\sum\limits_{k=1}^n\sum\limits_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{k}\rfloor}[gcd(i,j)=1](k\in prime)
\]
因为
\[\begin{array} \ \because \sum\limits_{d∣n}\mu(d)=[n=1] \\ \therefore \sum\limits_{d∣gcd(i,j)}μ(d) = [gcd(i,j)=1] \end{array}
\]
所以可以把\([gcd(i,j)=1]\)替换掉,即
\[\sum\limits_{k=1}^n\sum\limits_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{k}\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d)(k\in prime)
\]
将\(d\)提前,同时把\(i,j\)除以\(d\)
\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{i=1}^{\lfloor \frac{n}{kd}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{kd}\rfloor}\mu(d)(k\in prime)
\]
发现后面两个可以变成整除分块
\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{kd}\rfloor\lfloor \frac{m}{kd}\rfloor(k\in prime)
\]
对于\(\lfloor \frac{n}{kd}\rfloor\)这种形式,可以进一步降低复杂度。
设\(T=kd\)
\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor(k\in prime)
\]
把\(d\)换成\(T\)
\[\sum\limits_{T=1}^n\sum\limits_{k|T}\mu(\frac{T}{k})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor(k\in prime)
\]
调整一下位置
\[\sum\limits_{T=1}^n\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor\sum\limits_{k|T}\mu(\frac{T}{k})(k\in prime)
\]
发现,\(\sum\limits_{k|T}\)后面的部分可以预处理出来,
在枚举质数时,对于每个质数\(k\)的倍数\(T\),\(sum[T]+=\mu(\frac{T}{k})\)
代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
#define MogeKo qwq
using namespace std;
const int maxn = 10000005;
int mu[maxn],prime[maxn],f[maxn],sum[maxn];
bool vis[maxn];
int t,n,m,cnt;
long long ans;
void Prime(){
mu[1] = 1;
for(int i = 2;i <= maxn-5;i++){
if(!vis[i]){
prime[++cnt] = i;
mu[i] = -1;
}
for(int j = 1;j<=cnt && i*prime[j]<=maxn-5;j++){
vis[i*prime[j]] = true;
if(i%prime[j] == 0)break;
mu[i*prime[j]] = -1*mu[i];
}
}
}
void Sum(){
for(int j = 1;j <= cnt;j++)
for(int i = 1;i*prime[j] <= maxn-5;i++)
f[i*prime[j]] += mu[i];
for(int i = 1;i <= maxn-5;i++)
sum[i] = sum[i-1]+f[i];
}
int main(){
scanf("%d",&t);
Prime();
Sum();
while(t--){
scanf("%d%d",&n,&m);
ans = 0;
for(int l = 1,r = 0;l <= min(n,m);l=r+1){
r = min(n/(n/l),m/(m/l));
ans += (long long)(n/l) * (m/l) * (sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}