Luogu5176 公约数

Arahc 11.0

题面

简化题意

f(i,j,k)=gcd(i,j)gcd(i,k)gcd(j,k)f(i,j,k) = \frac{\gcd(i,j)}{\gcd(i,k)\gcd(j,k)},求下面式子的值,对 109+710^9+7 取模:

i=1nj=1mk=1pgcd(ij,ik,jk)gcd(i,j,k)(f(i,j,k)+f(i,k,j)+f(j,k,i))\sum_{i=1}^n \sum_{j=1}^m \sum_{k=1}^p \gcd(ij,ik,jk)\gcd(i,j,k)(f(i,j,k)+f(i,k,j)+f(j,k,i))

多测,T103,n,m,p2×107T\leq 10^3,n,m,p\leq 2\times 10^7

题解

考虑唯一分解定理,将 gcd(ij,jk,ik)\gcd(ij,jk,ik) 先干掉:将 i,j,ki,j,k 两两的公共质因子的并,去掉 i,j,ki,j,k 都有的质因子,剩下的部分就是 ij,jk,ikij,jk,ik 的质因子的交。也就是:

gcd(ij,ik,jk)gcd(i,j,k)=gcd(i,j)gcd(i,k)gcd(i,k)\gcd(ij,ik,jk)\gcd(i,j,k) = \gcd(i,j)\gcd(i,k)\gcd(i,k)

接下来考虑三个 ff 的和。设 a=gcd(i,j),b=gcd(i,k),c=gcd(j,k)a=\gcd(i,j),b=\gcd(i,k),c=\gcd(j,k),则那三个和可以写成 abc+bac+cab\frac{a}{bc}+\frac{b}{ac}+\frac{c}{ab}。通分一下,代回原式:

i=1nj=1mk=1pgcd(i,j)2+gcd(i,k)2+gcd(j,k)2\sum_{i=1}^n \sum_{j=1}^m \sum_{k=1}^p \gcd(i,j)^2+\gcd(i,k)^2+\gcd(j,k)^2

F(n,m,p)=pinjmgcd(i,j)2F(n,m,p) = p \sum_i^n \sum_j^m \gcd(i,j)^2。显然只要能求出一个 FF 怎么算原问题就解决里。

考虑后面的 gcd(i,j)2\gcd(i,j)^2 很莫反:

d=1min(n,m)d2i=1ndj=1mdkgcd(i,j)μ(k)\sum_{d=1}^{\min(n,m)} d^2 \sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor} \sum_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor} \sum_{k\mid \gcd(i,j)} \mu(k)

然后交换 \sum

d=1min(n,m)d2k=1min(n,m)dμ(k)ndkmdk\sum_{d=1}^{\min(n,m)} d^2 \sum_{k=1}^{\left\lfloor\frac{\min(n,m)}{d}\right\rfloor} \mu(k) \left\lfloor\frac{n}{dk}\right\rfloor \left\lfloor\frac{m}{dk}\right\rfloor

然后换元,设 t=dkt=dk

p=1nnpmpdpd2μ(pd)\sum_{p=1}^n \left\lfloor\frac{n}{p}\right\rfloor \left\lfloor\frac{m}{p}\right\rfloor \sum_{d\mid p} d^2\mu(\frac{p}{d})

整除分块,后面是一个 id2μ\rm{id}^2\ast\mu 的形式。可以杜教筛。不过数据范围开得比较小,线性筛就能过了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int max_n=20000007,N=20000000,mod=1000000007;
inline int read(){
int x=0;bool w=0;char c=getchar();
while(c<'0' || c>'9') w|=c=='-',c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}

bool isp[max_n];
int pr[max_n],cntp,mu[max_n],f[max_n];

inline void Getpr(int n){
memset(isp,1,sizeof(isp)),isp[1]=0;
mu[1]=f[1]=1;
for(register int i=2;i<=n;++i){
if(isp[i]){
pr[++cntp]=i;
mu[i]=-1,
f[i]=(i*i-1)%mod;
}
for(register int j=1;i*pr[j]<=n && j<=cntp;++j){
isp[i*pr[j]]=0;
if(i%pr[j]==0){
mu[i*pr[j]]=0,
f[i*pr[j]]=f[i]*pr[j]*pr[j]%mod;
break;
}
mu[i*pr[j]]=-mu[i],
f[i*pr[j]]=f[i]*f[pr[j]]%mod;
}
}
for(register int i=1;i<=n;++i)
f[i]=(f[i-1]+f[i])%mod;
}

inline int F(int n,int m){
int res=0,up=min(n,m);
for(register int l=1,r;l<=up;l=r+1){
r=min(n/(n/l),m/(m/l));
res=(res+(n/l)*(m/l)%mod*(f[r]-f[l-1]+mod)%mod)%mod;
}
return res;
}

signed main(){
Getpr(N);
for(register int T=read();T>0;--T){
int n=read(),m=read(),p=read();
write((p*F(n,m)+m*F(n,p)+n*F(m,p))%mod),putchar('\n');
}
return 0;
}
  • 标题: Luogu5176 公约数
  • 作者: Arahc
  • 创建于 : 2022-02-28 08:00:00
  • 更新于 : 2023-03-19 06:31:54
  • 链接: https://arahc.github.io/2022/02/28/【题解】Luogu5176-公约数/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
Luogu5176 公约数