luogu P4619 [SDOI2018]旧试题
先考虑\(d(i,j,k)\)是啥,首先会有\(d(i,j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\),可以推广得到\(d(i,j,k)=\sum_{x|i}\sum_{y|j}\sum_{z|k}[gcd(x,y)=1][gcd(y,z)=1][gcd(x,z)=1]\),然后开始化式子
\(\sum_{i=1}^{A}\sum_{j=1}^{B}\sum_{k=1}^{C}\sum_{x|i}\sum_{y|j}\sum_{z|k}[gcd(x,y)=1][gcd(y,z)=1][gcd(x,z)=1]\)
\(\sum_{i=1}^{A}\sum_{j=1}^{B}\sum_{k=1}^{C}\sum_{x|i}\sum_{y|j}\sum_{z|k}\sum_{a|x,a|y}\mu(a)\sum_{b|y,b|z}\mu(b)\sum_{c|z,c|x}\mu(c)\)
\(\sum_{a=1}^{\min(A,B)}\sum_{b=1}^{\min(B,C)}\sum_{c=1}^{\min(C,A)}\mu(a)\mu(b)\mu(c)\sum_{\mathrm{lcm}(c,a)|x}\sum_{\mathrm{lcm}(a,b)|y}\sum_{\mathrm{lcm}(b,c)|z}\lfloor\frac{A}{x}\rfloor\lfloor\frac{B}{y}\rfloor\lfloor\frac{C}{z}\rfloor\)
这里记\(F_A(x)=\sum_{x|i}\lfloor\frac{A}{i}\rfloor\),\(F_B(x),F_C(x)\)同理,可得
\(\sum_{a=1}^{\min(A,B)}\sum_{b=1}^{\min(B,C)}\sum_{c=1}^{\min(C,A)}\mu(a)\mu(b)\mu(c)F_A(\mathrm{lcm}(c,a))F_B(\mathrm{lcm}(a,b))F_C(\mathrm{lcm}(b,c))\)
到这个时候就可以讨论了,首先是\(a=b=c\)的情况,可以做到\(O(n)\)统计;然后是\(abc\)中两个相等且另外一个不相等,以及三个都不相等的情况.答案的这个形式就是枚举三个不同的数,然后考虑他们两两之间的贡献,可以联想到建图,连上所有的\((a,b,\mathrm{lcm}(a,b))\)即可套三元环计数.然后我们显然只用考虑\(\mu(a)\neq 0,\mu(b)\neq 0,\mathrm{lcm}(a,b)\le \max\{A,B,C\}\)的边,可以发现这样的边只有约\(8*10^5\)条,所以如果是\(abc\)中两个相等且和另外一个不相等的情况,就是一次枚举每条边,然后枚举这条边会对应的\(aab,abb,aac,acc,bbc,bcc\)六种情况;如果是\(abc\)都不相等,那么对应到图上就是枚举一个三元环,所以使用三元环计数即可,枚举三元环复杂度\(O(|E|^{1.5})\),再讨论这三个点分别\(abc\)中的哪个来统计答案
然后这题较卡常,首先\(F_A,F_B,F_C\)可以\(O(nlogn)\)预处理;然后是建图问题,因为\(\mathrm{lcm}(a,b)=\gcd(a,b)\frac{a}{\gcd(a,b)}\frac{b}{\gcd(a,b)}\),那么只要枚举\(\gcd(a,b)\frac{a}{\gcd(a,b)}\frac{b}{\gcd(a,b)}\)并且保证他们的乘积\(\le \max\{A,B,C\}\),可以发现这个复杂度类似调和极数,为\(O(nlog^2n)\);还有就是能并在一起计算的式子最好并在一起
#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
using namespace std;
const int N=1e5+10,M=N*10,mod=1e9+7;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
return x*w;
}
/*int to[M],nt[M],w[M],hd[N],tot=1;
void adde(int x,int y,int z){++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;}*/
void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int prm[N],pp[N],f[N],g[N],h[N],mu[N],tt,nm[N],tn,id[N],dg[N],vs[N],te;
int n,a,b,c,ans;
void inii(int *f,int nn)
{
memset(f,0,sizeof(int)*(n+1));
for(int i=1;i<=nn;++i)
for(int j=1;i*j<=nn;++j)
ad(f[i],nn/(i*j));
}
struct node{int x,y,z;}ee[M];
vector<node> gg[N];
vector<node>::iterator i1,i2;
int main()
{
///wdnmd
mu[1]=1;
for(int i=2;i<=N-5;++i)
{
if(!pp[i]) pp[i]=1,prm[++tt]=i,mu[i]=-1;
for(int j=1;i*prm[j]<=N-5;++j)
{
if(i%prm[j]==0){pp[i*prm[j]]=pp[i]+1;break;}
pp[i*prm[j]]=1,mu[i*prm[j]]=-mu[i];
}
}
for(int i=1;i<=N-5;++i)
if(mu[i]) nm[++tn]=i,id[i]=tn;
int lt=tn,T=rd();
while(T--)
{
a=rd(),b=rd(),c=rd();
n=max(max(a,b),c);
inii(f,a),inii(g,b),inii(h,c);
tn=lt;
while(nm[tn]>n) --tn;
te=0;
memset(dg,0,sizeof(int)*(n+1))/*,memset(hd,0,sizeof(int)*(n+1)),tot=1*/;
for(int d=1;d<=n;++d)
for(int i=1;1ll*i*d<=n;++i)
for(int j=i+1;1ll*i*j*d<=n;++j)
if(mu[i*d]&&mu[j*d]&&gcd(i,j)==1) ++dg[id[i*d]],++dg[id[j*d]],ee[++te]=(node){id[i*d],id[j*d],i*j*d};
for(int i=1;i<=tn;++i) gg[i].clear();
for(int i=1;i<=te;++i)
{
int x=ee[i].x,y=ee[i].y,z=ee[i].z;
if(dg[x]>dg[y]) swap(x,y);
gg[x].push_back((node){i,y,z});
}
ans=0;
for(int x=1;x<=tn;++x)
{
for(i1=gg[x].begin();i1!=gg[x].end();++i1)
{
int i=(*i1).x,y=(*i1).y,xx=nm[x],yy=nm[y],w=(*i1).z;
vs[y]=i;
int nw=(1ll*f[xx]*g[w]%mod*h[w]+1ll*f[w]*g[xx]%mod*h[w]+1ll*f[w]*g[w]%mod*h[xx])%mod;
ad(ans,(~(mu[xx]*mu[xx]*mu[yy])?nw:mod-nw));
nw=(1ll*f[yy]*g[w]%mod*h[w]+1ll*f[w]*g[yy]%mod*h[w]+1ll*f[w]*g[w]%mod*h[yy])%mod;
ad(ans,(~(mu[xx]*mu[yy]*mu[yy])?nw:mod-nw));
}
for(i1=gg[x].begin();i1!=gg[x].end();++i1)
{
int i=(*i1).x,y=(*i1).y;
for(i2=gg[y].begin();i2!=gg[y].end();++i2)
{
int j=(*i2).x,z=(*i2).y;
if(vs[z])
{
int k=vs[z],w1=ee[i].z,w2=ee[j].z,w3=ee[k].z;
int nw=(1ll*f[w1]*g[w2]%mod*h[w3]+1ll*f[w1]*g[w3]%mod*h[w2]+1ll*f[w2]*g[w1]%mod*h[w3]+1ll*f[w2]*g[w3]%mod*h[w1]+1ll*f[w3]*g[w1]%mod*h[w2]+1ll*f[w3]*g[w2]%mod*h[w1])%mod;
ad(ans,(~(mu[nm[x]]*mu[nm[y]]*mu[nm[z]])?nw:mod-nw));
}
}
}
for(i1=gg[x].begin();i1!=gg[x].end();++i1) vs[(*i1).y]=0;
}
for(int i=1;i<=tn;++i)
{
int nw=1ll*f[nm[i]]*g[nm[i]]%mod*h[nm[i]]%mod;
ad(ans,(~(mu[nm[i]]*mu[nm[i]]*mu[nm[i]])?nw:mod-nw));
}
printf("%d\n",ans);
}
return 0;
}