Evanyou Blog 彩带

洛谷P2398 GCD SUM [数论,欧拉筛]

  题目传送门

GCD SUM

题目描述

for i=1 to n

for j=1 to n

sum+=gcd(i,j)

给出n求sum. gcd(x,y)表示x,y的最大公约数.

输入输出格式

输入格式:

n

输出格式:

sum

输入输出样例

输入样例#1: 
2
输出样例#1: 
5

说明

数据范围 30% n<=3000 60% 7000<=n<=7100 100% n<=100000


  分析:

  无聊的出题人出的无聊的数学题。

  这里博主用了一种比较暴力的思想,直接枚举以$1\thicksim n$为$GCD$的数对个数,然后累加得到答案就行了,然后就不难得到公式:

  $ans=\sum^n_{i=1}((\sum^{\lfloor n/i\rfloor}_{j=1} \phi(i)-1)*i+i)$

  Code:

 

//It is made by HolseLee on 27th Oct 2018
//Luogu.org P2398
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
const ll N=1e5+7;
ll n,phi[N],sum[N],q[N],top,ans;
bool vis[N];

void ready()
{
    phi[1]=1;
    for(ll i=2; i<=n; ++i) {
        if( !vis[i] ) phi[q[++top]=i]=i-1;
        for(ll j=1,k; j<=top && (k=q[j]*i)<=n; ++j) {
            vis[k]=1;
            if( i%q[j] ) phi[k]=phi[i]*(q[j]-1);
            else { phi[k]=phi[i]*q[j]; break; }
        }
    }
    for(ll i=2; i<=n; ++i) sum[i]=sum[i-1]+phi[i];
}

int main()
{
    scanf("%lld",&n);
    ready(); ll now;
    for(ll i=1; i<=n; ++i) {
        now=n/i;
        //cout<<sum[now]<<' '<<i<<'\n';
        ans+=sum[now]*i*2+i;
    }
    printf("%lld\n",ans);
    return 0;
}

 

 

                                                                                        

posted @ 2018-10-28 20:00  HolseLee  阅读(271)  评论(0编辑  收藏  举报