这道题和
∑ni=1∑mj=1LCM(i,j)
很像,但是这道题n和m是相同的,而且需要
O(1)
询问
所以尝试设
f(n)=∑ni=1∑nj=1LCM(i,j)
,但
f
不是积性函数,所以不考虑i,重新定义
(这是个n*n的LCM的矩阵,横坐标是i,纵坐标是j,每个位置存了LCM(i,j),那么答案就是整个矩阵的和,而f的前缀和是矩阵里过对角线的一个三角形)
设
g(n)=∑ni=1i[gcd(i,n)=1]
,则
g(n)=n∗φ(n)2+12[n=1]
,
f(n)=n(∑d|ng(nd)+12)
,但是这样两个函数都不是积性函数,也没法预处理 ,所以令
g(n)∗2−1
,得
g(n)=n∗φ(n)
,这样
g(n)
就是积性函数,
f(n)
也是了(不考虑前面的系数n),然后就可以线性筛
f,g
和
f
的前缀和,因为原来的
出题人你取个模能死?非要我打高精…….
code: (程序里的f是上文的g,g是上文的f)
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1000001;
const long long M = 1e9;
struct ll
{
long long a,b;
ll(){}
ll(long long _a,long long _b)
{
a=_a;b=_b;
a+=b/M;
b%=M;
}
};
ll operator +(ll a,ll b)
{
ll ret=a;
ret.a+=b.a; ret.b+=b.b;
ret.a+=ret.b/M; ret.b%=M;
return ret;
}
ll operator -(ll a,ll b)
{
ll ret=a;
ret.a-=b.a;
if(ret.b<b.b)ret.a--,ret.b+=M;
ret.b-=b.b;
return ret;
}
ll operator *(ll a,ll b)
{
ll ret;
ret.a=a.a*b.a+a.b*b.a+a.a*b.b;
ret.a+=a.b*b.b/M;
ret.b=a.b*b.b%M;
return ret;
}
void putout(ll x)
{
if(x.a)
{
printf("%lld",x.a);
printf("%09lld\n",x.b);
}
else printf("%lld\n",x.b);
}
long long p[maxn],pri,phi[maxn];
ll f[maxn],g[maxn],sum[maxn];
bool v[maxn];
long long n,m;
int main()
{
phi[1]=1;
f[1]=g[1]=ll(0,1); sum[1]=ll(0,1);
for(long long i=2;i<maxn;i++)
{
if(!v[i])
{
p[++pri]=i;
phi[i]=i-1;
f[i]=ll(0,i)*ll(0,phi[i]);
g[i]=f[i]+f[1];
}
for(long long j=1;j<=pri&&i*p[j]<maxn;j++)
{
long long k=p[j]*i;
v[k]=true;
if(i%p[j]==0)
{
phi[k]=phi[i]*p[j];
long long temp=k,tmp=1;
ll tt=ll(0,0);
while(temp%p[j]==0) temp/=p[j],tmp*=p[j],tt=tt+f[temp];
if(temp==1)
{
f[k]=ll(0,k)*ll(0,phi[k]);
g[k]=f[k]+tt;
}
else
{
f[k]=f[temp]*f[tmp];
g[k]=g[temp]*g[tmp];
}
break;
}
else
{
phi[k]=phi[i]*phi[p[j]];
f[k]=f[i]*f[p[j]];
g[k]=g[i]*g[p[j]];
}
}
sum[i]=sum[i-1]+g[i]*ll(0,i);
}
int t; scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
ll ans=sum[n];
putout(ans);
}
return 0;
}