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=1n∑j=1n∑d=1n[gcd(i,j)=d]phi[d]
=∑d=1nphi[d]∗2∑i=1n/d∑j=1n/d(phi[i]−1)=∑d=1nphi[d]∗2∑i=1n/d∑j=1n/d(phi[i]−1)
因为gcd(i,j)=1实际上就是互质,也就是欧拉函数嘛
于是我们可以把phi前缀和一下
然后分块加速
复杂度O(n∗T(sqrt(n)))O(n∗T(sqrt(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;
}

本文介绍了一道使用莫比乌斯反演求解的数学问题,通过将三重循环转化为更简洁的形式来提高计算效率。文章给出了具体的实现代码,并采用分块技术将复杂度降低到O(n*T(sqrt(n)))。

2131

被折叠的 条评论
为什么被折叠?



