Description
给出一个数字N
Input
第一行为一个正整数T,表示数据组数。 接下来T行为询问,每行包含一个正整数N。 T<=5000,N<=10^7
Output
按读入顺序输出答案。
Sample Input
1
10
Sample Output
136
题解
先上一手莫反
∑i=1n∑j=1n∑d=1n[gcd(i,j)=d]phi[d] ∑ i = 1 n ∑ j = 1 n ∑ d = 1 n [ g c d ( i , j ) = d ] p h i [ d ]
=∑d=1nphi[d]∗2∑i=1n/d∑j=1n/d(phi[i]−1) = ∑ d = 1 n p h i [ d ] ∗ 2 ∑ i = 1 n / d ∑ j = 1 n / d ( p h i [ i ] − 1 )
因为gcd(i,j)=1实际上就是互质,也就是欧拉函数嘛
于是我们可以把phi前缀和一下
然后分块加速
复杂度 O(n∗T(sqrt(n))) O ( n ∗ T ( s q r t ( n ) ) )
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL sum[11000000];
int phi[11000000],pri[11100000],pr;
bool v[11000000];
void getphi(int MAXN)
{
phi[1]=1;memset(v,true,sizeof(v));
for(int i=2;i<=MAXN;i++)
{
if(v[i])
{
pri[++pr]=i;
phi[i]=i-1;
}
for(int j=1;j<=pr && i*pri[j]<=MAXN;j++)
{
v[i*pri[j]]=false;
if(i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
else phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
for(int i=1;i<=MAXN;i++)sum[i]=sum[i-1]+phi[i];
}
int n;
int main()
{
int T;scanf("%d",&T);getphi(10000000);
while(T--)
{
scanf("%d",&n);
LL ans=0;int next;
for(register int d=1;d<=n;d=next+1)
{
next=n/(n/d);
ans+=(LL)(sum[next]-sum[d-1])*sum[n/d];
}
printf("%lld\n",2LL*ans-sum[n]);
}
return 0;
}