传送门
题解:
首先我们知道 g c d gcd gcd和 l c m lcm lcm都是可以分质因子来算的,感觉可能会和积性函数沾边。
所以很显然地,我们设 f ( n ) = ∑ i = 1 n ∑ j = 1 n l c m ( g c d ( i , n ) , g c d ( j , n ) ) f(n)=\sum\limits_{i=1}^n\sum\limits_{j=1}^nlcm(gcd(i,n),gcd(j,n)) f(n)=i=1∑nj=1∑nlcm(gcd(i,n),gcd(j,n))。
容易发现 f ( n ) f(n) f(n)是个积性函数,现在需要算前缀和。
于是我们首先考虑质数点值,很显然地,质数点值就是 f ( p ) = 3 ( p 2 − p ) + 1 f(p)=3(p^2-p)+1 f(p)=3(p2−p)+1
然后我们考虑 f ( p k ) f(p^k) f(pk)。。。
具体过程我就不放上来了,反正我这种数学弱菜就只能各种暴力展开,各种特判,各种公式套,这里主要就是展开后等比数列求和,我们可以得到:
f ( p k ) = ( 2 k + 1 ) ( p 2 k − p 2 k − 1 ) + p k − 1 f(p^k)=(2k+1)(p^{2k}-p^{2k-1})+p^{k-1} f(pk)=(2k+1)(p2k−p2k−1)+pk−1
直接上min_25筛即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
#define uint unsigned int
using std::cerr;
inline ll S1(ll n){return n*(n+1)>>1;}
inline ll S2(ll n){
switch(n%6){
case 1:return (n+1)*(2*n+1)/6*n;
case 4:return n*(2*n+1)/6*(n+1);
default:return n*(n+1)/6*(2*n+1);
}
}
cs int N=1e5+7;
int n,lim,tot,p[N];
uint c1[N],c2[N],s1[N],s2[N],f1[N],f2[N];
inline void init(){
lim=sqrt(n),tot=0;
for(int re i=1;i<=lim;++i){
c1[i]=i-1;c2[i]=n/i-1;
s1[i]=S1(i)-1;s2[i]=S1(n/i)-1;
f1[i]=S2(i)-1;f2[i]=S2(n/i)-1;
}
for(uint re p=2;p<=lim;++p)if(c1[p]!=c1[p-1]){
::p[++tot]=p;
uint p2=p*p,c=c1[p-1],s=s1[p-1],f=f1[p-1];
for(int re i=1,li=lim/p;i<=li;++i){
c2[i]-=c2[i*p]-c;
s2[i]-=(s2[i*p]-s)*p;
f2[i]-=(f2[i*p]-f)*p2;
}
for(int re i=lim/p+1,li=std::min(n/p/p,(uint)lim);i<=li;++i){
c2[i]-=c1[n/i/p]-c;
s2[i]-=(s1[n/i/p]-s)*p;
f2[i]-=(f1[n/i/p]-f)*p2;
}
for(int re i=lim,li=p*p;li<=i;--i){
c1[i]-=c1[i/p]-c;
s1[i]-=(s1[i/p]-s)*p;
f1[i]-=(f1[i/p]-f)*p2;
}
}
for(int re i=1;i<=lim;++i){
f1[i]=3*(f1[i]-s1[i])+c1[i];
f2[i]=3*(f2[i]-s2[i])+c2[i];
}
}
inline uint solve(int n,int i){
uint ans=(n<=lim?f1[n]:f2[::n/n])-f1[p[i-1]];
for(int re j=i;j<=tot;++j){
if(p[j]*p[j]>n)break;
uint p1=p[j]*(p[j]-1),p2=1,sp=p[j]*p[j];
for(ll now=p[j],t=1;now<=n;now*=p[j],++t){
if(now*p[j]<=n)ans+=((2*t+1)*p1+p2)*solve(n/now,j+1);
if(t>1)ans+=(2*t+1)*p1+p2;
p1*=sp,p2*=p[j];
}
}
return ans;
}
signed main(){
int T;std::cin>>T;
while(T--){
std::cin>>n;init();
std::cout<<solve(n,1)+1<<"\n";
}
return 0;
}