【欧拉函数】uva 11426 GCD - Extreme (II)

题意:求\(G(n)\)

$$G(n)=\sum_{1\leqslant i< j\leqslant n}\gcd (i,j)$$



设\(f(n)=\sum_{i=1}^{n-1}\gcd (i,n) \)


则\(G(n)=\sum_{i=2}^{n}f(n)\)


可得递推公式\(G(n)=G(n-1)+f(n)\)


所有\(\gcd (x, n)\)的值都是n的约数,按照约数进行分类,令\(p(n, d)\)表示满足\(\gcd (x, n) = d(x<n) \)的正整数x的个数,则\(f(n)=\sum_{d|n}p(n,d)d\)


\(\gcd (x, n) = d\)的充要条件为\(\gcd (\frac{x}{d}, \frac{n}{d}) = 1\),因此满足条件的\(\frac{x}{d}\)有\(\phi(\frac{n}{d})\)个,则\(f(n)=\sum_{d|n}\phi(\frac{n}{d})d\)


如果依次计算\(f(n)\),枚举\(f(n)\)的约数的话效率太低


因此对于每个\(d\)枚举它的倍数\(n\)并更新\(f(n)\),时间复杂度\(O(n\log (n))\)。



#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))

#define N 4000010
#define INF 1<<30
#define ll long long

ll euler[N];
ll sum[N];

void getEuler(){
    memset(euler,0,sizeof(euler));
    euler[1]=1;
    for(int i=2;i<=N;++i){
        if(!euler[i]){
            for(int j=i;j<=N;j+=i){
                if(!euler[j])
                    euler[j]=j;
                euler[j]=euler[j]/i*(i-1);
            }
        }
    }
}

void getSum(){

    for(int i=1;i<=N;++i)
        for(int j=i*2;j<=N;j+=i)
            sum[j]+=euler[j/i]*i;
    for(int i=3;i<=N;++i)
        sum[i]+=sum[i-1];
}


int main(){
	//freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
	ll n;
	getEuler();
	getSum();
	while(scanf("%lld",&n),n){
        printf("%lld\n",sum[n]);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值