uva11426 GCD Extreme(II)

时间:2023-08-30 16:08:20

题意:求sum(gcd(i,j),1<=i<j<=n)1<n<4000001

思路:

1.建立递推关系,s(n)=s(n-1)+gcd(1,n)+gcd(2,n)+……+gcd(n-1,n);

2.设f(n)=gcd(1,n)+gcd(2,n)+……+gcd(n-1,n)。

gcd(x,n)=i是n的约数(x<n),按照这个约数进行分类。设满足gcd(x,n)=i的约束有g(n,i)个,则有f(n)=sum(i*g(n,i))。

而gcd(x,n)=i等价于gcd(x/i,n/i)=1,因此g(n,i)等价于phi(n/i).phi(x)为欧拉函数。

3.降低时间复杂度。用筛法预处理phi[x]表

用筛法预处理f(x)->枚举因数,更新其所有倍数求解。

 #include <iostream>
#include <cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<vector>
#include<cassert> using namespace std;
const int maxn = ;
#define LL long long
#define clc(a,b) memset(a,b,sizeof(a))
LL S[maxn],f[maxn];
LL phi[maxn];
void phi_table(int n)
{
for(int i=;i<=n;i++)
phi[i]=;
phi[]=;
for(int i=;i<=n;i++)
{
if(phi[i]==)
{
for(int j=i;j<=n;j+=i)
{
if(!phi[j])
phi[j]=j;
phi[j]=phi[j]/i*(i-);
}
}
}
} int main()
{
phi_table(maxn);
clc(f,);
for(int i=;i<=maxn;i++)
{
for(int n=i*;n<=maxn;n+=i)
f[n]+=i*phi[n/i];
}
S[]=f[];
for(int n=;n<=maxn;n++)
S[n]=S[n-]+f[n];
int n;
while(scanf("%d",&n),n)
{
printf("%lld\n",S[n]);
}
return ;
}