P5176 公约数
说在前面的话:
这题后面的线性筛和 P4449 于神之怒加强版 很像,建议这两道题连着做,巩固一下非常规函数线性筛顺便水个双倍经验。但是网上于神之怒的题解都过于简略(我比较菜),看不懂,做于神之怒的时候很痛苦,因此本文线性筛的过程尽量详细写,让初学者看懂,看不懂欢迎在评论区提问,NOIP前应该能做到1天内回复。
那个 \(\gcd(ij,jk,ki)\) 一看就是要化掉的。
显然应该从质因子的幂次入手,设 \(i=p^a,j=p^b,k=p^c\)
那么 \(p\) 对 \(\gcd(ij,jk,,ki)\) 的贡献就是 \(p^{\min(a+b,b+c,c+a)}\)
考虑构造一个东西来表示 \(\min(a+b,b+c,c+a)\) 。不妨 \(a\le b\le c\) (显然排序不会影响结果)
\(\min(a+b,b+c,c+a)=a+b=\min(a,b)+\min(b,c)+\min(a,c)-\min(a,b,c)\)
转成 \(\gcd\) 的写法就是 \(\gcd(ij,jk,ki)=\dfrac{\gcd(i,j)\gcd(j,k)\gcd(k,i)}{\gcd(i,j,k)}\)
带回原式发现良心出题人非常非常非常良心地帮你约掉了 \(\gcd(i,j,k)\) 这种三元 \(\gcd\) 以及所有分母
化简一下,原式\(=\sum\limits_{i=1}^{A}\sum\limits_{j=1}^{B}\sum\limits_{k=1}^{C}\gcd(i,j)^2+\gcd(j,k)^2+\gcd(k,i)^2\)
发现凉心出题人非常非常非常凉心把 \(\gcd\) 平方了。
原式显然可以分成三部分算。
先算
现在的问题在于 \(f(T)=\sum_{d|T}d^2\mu(\dfrac{T}{d})\) ,这个东西一出来就可以 \(O(\sqrt{n})\) 整除分块了。
仔细观察发现这是个积性函数,可以线性筛, \(2e7\) 怕他啥(\(\color{black}{\texttt{c}}\color{red}{\texttt{yn2006}}\) \(O(n\ln n)\) 暴力筛都过去了)。
令 \(p\in prime\) ,则
接下去处理掉 \(p|i\) 的情况就可以线性筛了。
设 \(x\) 为 \(p\) 在 \(T\) 中的最高幂次
发掘 \(\mu\) 的性质,当且仅当 \(d=p^x\) 或 \(d=p^{x-1}\) 时有贡献(\(\mu(\dfrac{T}{d})!=0\))。
带入得
\(f(p^x)=p^{2x}-p^{2(x-1)}\)
\(f(p^{x+1})=p^{2(x+1)}-p^{2x}=p^2(p^{2x}-p^{2(x-1)})=p^2f(p^x)\)
\(\therefore f(ip)=f(i)\times p^2(p|i)\) ,综合如下:
可以线性筛了
提供一组大样例以供调试
Input
1
10000000 5000000 20000000
Output
913785109
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N=20000005;
const int mod=1000000007;
int A,B,C;
int pri[N/10],cnt,s[N];
bool vis[N];
void Sieve(const int N=20000000){
s[1]=1;
for(int i=2;i<=N;++i){
if(!vis[i])pri[++cnt]=i,s[i]=1ll*i*i%mod-1;
for(int j=1;j<=cnt&&i*pri[j]<=N;++j){
vis[i*pri[j]]=1;
if(i%pri[j]==0){s[i*pri[j]]=1ll*s[i]*pri[j]%mod*pri[j]%mod;break;}
s[i*pri[j]]=1ll*s[i]*s[pri[j]]%mod;
}
}
for(int i=1;i<=N;++i)s[i]=(s[i]+s[i-1])%mod;
}
int f(int A,int B,int C){
int res=0;
for(int l=1,r,mx=min(A,B);l<=mx;l=r+1){
r=min(A/(A/l),B/(B/l));
res=(res+1ll*(A/l)*(B/l)%mod*(s[r]-s[l-1])%mod)%mod;
}
return 1ll*res*C%mod;
}
signed main(){
Sieve();
for(int T=read();T;--T){
A=read(),B=read(),C=read();
printf("%d\n",(((f(A,B,C)+f(B,C,A))%mod+f(C,A,B))%mod+mod)%mod);
}
}