欧拉函数 - GCD - Extreme (II) - UVA 11426
题意:
给 定 正 整 数 N , 计 算 : 给定正整数N,计算: 给定正整数N,计算:
G = ∑ i = 1 i < N ∑ j = i + 1 j ≤ N G C D ( i , j ) G=\sum_{i=1}^{i<N}\sum_{j=i+1}^{j≤N}GCD(i,j) G=i=1∑i<Nj=i+1∑j≤NGCD(i,j)
其 中 , G C D ( i , j ) 表 示 i 和 j 的 最 大 公 约 数 。 其中,GCD(i,j)表示i和j的最大公约数。 其中,GCD(i,j)表示i和j的最大公约数。
输入:
多 组 测 试 数 据 , 读 到 0 为 止 。 多组测试数据,读到0为止。 多组测试数据,读到0为止。
每 组 包 括 一 个 正 整 数 N ( 1 < N < 4000001 ) 。 每组包括一个正整数N(1 < N < 4000001)。 每组包括一个正整数N(1<N<4000001)。
输出:
一 个 正 整 数 , 表 示 答 案 。 一个正整数,表示答案。 一个正整数,表示答案。
Sample Input
10
100
200000
0
Sample Output
67
13015
143295493160
分析:
∑ i = 1 i < N ∑ j = i + 1 j ≤ N G C D ( i , j ) = ∑ j = 1 j ≤ N ∑ i = 1 j − 1 G C D ( i , j ) \sum_{i=1}^{i<N}\sum_{j=i+1}^{j≤N}GCD(i,j)=\sum_{j=1}^{j≤N}\sum_{i=1}^{j-1}GCD(i,j) i=1∑i<Nj=i+1∑j≤NGCD(i,j)=j=1∑j≤Ni=1∑j−1GCD(i,j)
即 对 所 有 的 j ∈ [ 1 , N ] , 求 [ 1 , j − 1 ] 中 的 所 有 数 与 j 的 最 大 公 约 数 的 和 。 即对所有的j∈[1,N],求[1,j-1]中的所有数与j的最大公约数的和。 即对所有的j∈[1,N],求[1,j−1]中的所有数与j的最大公约数的和。
记 G C D ( i , j ) = g , 则 : 记GCD(i,j)=g,则: 记GCD(i,j)=g,则:
∑ j = 1 j ≤ N ∑ i = 1 j − 1 G C D ( i , j ) = ∑ g = 1 N g × ∑ j = 1 j ≤ N ∑ i = 1 j − 1 [ G C D ( i , j ) = g ] = ∑ g = 1 N g × ∑ j = 1 j ≤ ⌊ N g ⌋ ∑ i = 1 j − 1 [ G C D ( i , j ) = 1 ] \sum_{j=1}^{j≤N}\sum_{i=1}^{j-1}GCD(i,j)=\sum_{g=1}^{N}g×\sum_{j=1}^{j≤N}\sum_{i=1}^{j-1}[GCD(i,j)=g]=\sum_{g=1}^{N}g×\sum_{j=1}^{j≤\lfloor\frac{N}{g}\rfloor}\sum_{i=1}^{j-1}[GCD(i,j)=1] j=1∑j≤Ni=1∑j−1GCD(i,j)=g=1∑Ng×j=1∑j≤Ni=1∑j−1[GCD(i,j)=g]=g=1∑Ng×j=1∑j≤⌊gN⌋i=1∑j−1[GCD(i,j)=1]
问 题 转 化 为 , 对 每 一 个 g ∈ [ 1 , N ] , 统 计 [ 1 , j − 1 ] 中 与 j 互 质 的 数 的 个 数 , j ∈ [ 1 , N ] 。 问题转化为,对每一个g∈[1,N],统计[1,j-1]中与j互质的数的个数,j∈[1,N]。 问题转化为,对每一个g∈[1,N],统计[1,j−1]中与j互质的数的个数,j∈[1,N]。
由 此 发 现 , 我 们 需 要 预 处 理 [ 1 , ⌊ N g ⌋ ] 的 欧 拉 函 数 。 由此发现,我们需要预处理[1,\lfloor\frac{N}{g}\rfloor]的欧拉函数。 由此发现,我们需要预处理[1,⌊gN⌋]的欧拉函数。
答 案 即 : 答案即: 答案即:
∑ g = 1 N g × ∑ j = 1 j ≤ ⌊ N g ⌋ ϕ ( j ) \sum_{g=1}^{N}g×\sum_{j=1}^{j≤\lfloor\frac{N}{g}\rfloor}\phi(j) g=1∑Ng×j=1∑j≤⌊gN⌋ϕ(j)
最 后 我 们 枚 举 g , 计 算 上 式 。 最后我们枚举g,计算上式。 最后我们枚举g,计算上式。
优化:
① 、 预 处 理 ϕ ( i ) 的 前 缀 和 。 ①、预处理\phi(i)的前缀和。 ①、预处理ϕ(i)的前缀和。
② 、 由 于 我 们 枚 举 g , ⌊ N g ⌋ 的 值 可 能 重 复 , 这 里 利 用 整 除 分 块 优 化 。 ②、由于我们枚举g,\lfloor\frac{N}{g}\rfloor的值可能重复,这里利用整除分块优化。 ②、由于我们枚举g,⌊gN⌋的值可能重复,这里利用整除分块优化。
故 还 需 预 处 理 前 缀 和 s u m [ x ] = ∑ i = 1 x i 。 \qquad故还需预处理前缀和sum[x]=\sum_{i=1}^xi。 故还需预处理前缀和sum[x]=∑i=1xi。
代码:
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=4e6+10;
int primes[N], cnt;
bool st[N];
ll f[N], sum[N], phi[N];
void get_prime(int n)
{
phi[1]=0;
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;primes[j]*i<=n;j++)
{
int p=primes[j];
st[p*i]=true;
if(i%p==0)
{
phi[p*i]=phi[i]*p;
break;
}
else phi[p*i]=(p-1)*phi[i];
}
}
for(int i=1;i<=n;i++) phi[i]+=phi[i-1];
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+i;
}
int main()
{
get_prime(N-1);
int n;
while(~scanf("%d",&n),n)
{
ll res=0;
for(int i=1,j; i<=n; i=j+1)
{
j=n/(n/i);
res+=phi[n/i]*(sum[j]-sum[i-1]);
}
printf("%lld\n",res);
}
return 0;
}