UVa 11426 GCD - Extreme (II) (欧拉函数应用·O(N*logN))

题意  令  G(n) = sum{gcd(i, j) | 0 < i < n, i < j <= n}  给你一个n  输出G(n)

令 F(n) = sum{gcd(i, n) | 0 < i < n} 

那么有递推式 G(n) = G(n-1) + F(n) , G(0)  = 0 

也就是说只用求出F(n) 就能递推求出 G(n)了  而求F(n)就比较容易了 

对于i  设 x < i , gcd(x,i) = 1 即x, n 互质  

 gcd(2*x, 2*i) = 2, gcd(3*x, 3*i) = 3, ..., gcd(k*x, k*i) = k  

这样的x的个数就是i的欧拉函数值  那么我们求出i的欧拉函数后  所有的F(k*i) 都加上k  这样筛一下就能求出一定范围内所有的F函数值了  然后累加上去就是G的函数值了

#include<cstdio>
const int N = 4000005;
typedef long long ll;
int phi[N];
ll g[N];

void init() //O(N*logN) 筛欧拉函数
{
    for(int i = 2; i < N; ++i) phi[i] = i;
    for(int i = 2; i < N; i ++)
    {
        if(phi[i] == i) //i是素数
        {
            for(int j = i; j < N; j += i)
                phi[j] = phi[j] / i * (i - 1);
            //需要从j中删除一个素因子i  因为phi(p^k) = (p-1) * p^(k-1)
        }
        for(int j = 1; j * i < N; j ++)
            g[j * i] += j * phi[i];
        //phi[i]是小于i且与i互质的数的个数 j * i < N 时 j * x 肯定也小于n
    }
    for(int i = 1; i < N; i ++) g[i] += g[i - 1];
}

int main()
{
    init();
    int n;
    while(scanf("%d", &n), n)
        printf("%lld\n", g[n]);
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值