題意
求 ∑ni=1lcm(i,n)
T<=300000
n<=1000000
分析
ans=∑ni=1lcm(i,n)
=∑ni=1i∗ngcd(i,n)
=∑d|n∑gcd(i,nd)=11<=i<=ndn∗i
=n∗∑d|n∑gcd(i,nd)=11<=i<=ndi
設F(d)=∑gcd(i,d)=11<=i<=di
則ans=n∗∑d|nF(d)
有一個結論就是F(d)=d∗ϕ(d)2
直接線篩預處理歐拉函數然後每次暴力求即可。
代碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000005
#define LL long long
using namespace std;
int tot,prime[N],phi[N];
bool not_prime[N];
void get_prime(int n)
{
phi[]=;
for (int i=;i<=n;i++)
{
if (!not_prime[i]) prime[++tot]=i,phi[i]=i-;
for (int j=;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=;
if (i%prime[j]==)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-);
}
}
}
LL solve(int n)
{
int w=sqrt(n);LL ans=+(LL)n*phi[n]/;
for (int i=;i<=w;i++)
if (n%i==)
{
ans+=(LL)i*phi[i]/;
if (n/i!=i) ans+=(LL)n/i*phi[n/i]/;
}
return ans*n;
}
int main()
{
get_prime();
int T;
scanf("%d",&T);
while (T--)
{
int n;
scanf("%d",&n);
printf("%lld\n",solve(n));
}
return ;
}