求
∑x=1A∑y=1B∑z=1Cd(xyz)
∑
x
=
1
A
∑
y
=
1
B
∑
z
=
1
C
d
(
x
y
z
)
类似这道题的结论,我们有
d(xyz)=∑i|x∑j|y∑k|z[(i,j)==1][(j,k)==1][(i,k)==1]
d
(
x
y
z
)
=
∑
i
|
x
∑
j
|
y
∑
k
|
z
[
(
i
,
j
)
==
1
]
[
(
j
,
k
)
==
1
]
[
(
i
,
k
)
==
1
]
于是带进去,就是求
莫比乌斯反演一下就是:
令 fx(n)=∑n|d⌊xd⌋ f x ( n ) = ∑ n | d ⌊ x d ⌋ ,这个东西显然可以nlogn预处理
我们注意到若n>x,那么 fx(n)=0 f x ( n ) = 0
令n=max(A,B,C)
那么只有当lcm(x,y)<=n时 fx(n) f x ( n ) 才有值。
因此我们对mu[x]!=0的点x建无向图。如果lcm(x,y)<=n就建边,边权为lcm(x,y)
对于所有三元环算贡献即可。建图要枚举lcm来建… O(nlog2n) O ( n l o g 2 n )
这样的话点数最多60794,边数最多760741.
但是你需要优美的枚举三元环才能通(卡)过!
比如去掉自环,把非三个不同点构成的三元环在外面枚举了。
比如ans最后再取模,不会爆ll。
比如给边定向,把无向图变成有向图。(度数小的向度数大的连边,这样才可以保证复杂度
O(mm−−√)
O
(
m
m
)
)
这样的话一个三元环只会被枚举到一次,即你枚举了无序三元组,你需要把六种情况全都统计了。
然后你枚举一个点x,再枚举一个它的出点y,再枚举一个出点z就好啦。
复杂度大概 O(∑(nlog2n)1.5) O ( ∑ ( n l o g 2 n ) 1.5 )
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define mod 1000000007
#define pa pair<int,int>
inline char gc(){
static char buf[1<<16],*S,*T;
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,prime[N>>3],tot=0,mu[N],m,du[N];
ll fa[N],fb[N],fc[N],sa[N],sb[N],sc[N],ans=0;
bool notprime[N];
struct E{
int u,v,w;
bool cmp(){return du[u]<du[v]||du[u]==du[v]&&u<v;}
}e[N*20];
vector<pa>eg[N];
inline void add(int x,int y,int w){eg[x].push_back(make_pair(y,w));}
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline void init(){
notprime[1]=1;mu[1]=1;
for(int i=2;i<=1e5;++i){
if(!notprime[i]) prime[++tot]=i,mu[i]=-1;
for(int j=1;prime[j]*i<=1e5;++j){
notprime[prime[j]*i]=1;
if(i%prime[j]==0){
mu[prime[j]*i]=0;break;
}mu[prime[j]*i]=-mu[i];
}
}
}
int main(){
// freopen("a.in","r",stdin);
int tst=read();init();
while(tst--){
int A=read(),B=read(),C=read();n=max(A,max(B,C));m=0;ans=0;
for(int i=1;i<=n;++i)
for(int j=i;j<=n;j+=i)
fa[i]+=A/j,fb[i]+=B/j,fc[i]+=C/j;
for(int i=1;i<=n;++i) ans+=mu[i]*mu[i]*mu[i]*fa[i]*fb[i]*fc[i];
for(int i=1;i<=n;++i)
for(int j=1;i*j<=n;++j){
if(!mu[i*j]) continue;
for(int k=1;i*j*k<=n;++k){
if(!mu[i*k]||k==j||gcd(j,k)!=1) continue;
int u=i*j,v=i*k,w=i*j*k,tmp=mu[u]*mu[u]*mu[v];
ans+=tmp*fa[u]*fb[w]*fc[w];
ans+=tmp*fb[u]*fa[w]*fc[w];
ans+=tmp*fc[u]*fa[w]*fb[w];
if(k<j) continue;e[++m].u=u;e[m].v=v;e[m].w=w;
du[u]++;du[v]++;
}
}
for(int i=1;i<=m;++i) if(e[i].cmp()) add(e[i].u,e[i].v,e[i].w);
else add(e[i].v,e[i].u,e[i].w);
for(int x=1;x<=n;++x){
for(int i=0;i<eg[x].size();++i){
int y=eg[x][i].first,w=eg[x][i].second;
sa[y]=fa[w];sb[y]=fb[w];sc[y]=fc[w];
}for(int i=0;i<eg[x].size();++i){
int y=eg[x][i].first,w1=eg[x][i].second;
for(int j=0;j<eg[y].size();++j){
int z=eg[y][j].first,w2=eg[y][j].second;
int tmp=mu[x]*mu[y]*mu[z];
ans+=tmp*fa[w1]*fb[w2]*sc[z];
ans+=tmp*fa[w1]*sb[z]*fc[w2];
ans+=tmp*fa[w2]*fb[w1]*sc[z];
ans+=tmp*fa[w2]*sb[z]*fc[w1];
ans+=tmp*sa[z]*fb[w1]*fc[w2];
ans+=tmp*sa[z]*fb[w2]*fc[w1];
}
}for(int i=0;i<eg[x].size();++i){
int y=eg[x][i].first,w=eg[x][i].second;
sa[y]=sb[y]=sc[y]=0;
}
}printf("%lld\n",ans%mod);
for(int i=1;i<=n;++i) fa[i]=fb[i]=fc[i]=0,eg[i].clear(),du[i]=0;
}return 0;
}