GCD - Extreme (II) for(i=1;i


/**
題目:GCD - Extreme (II)
鏈接:https://vjudge.net/contest/154246#problem/O
題意:
for(i=1;i<N;i++)
    for(j=i+1;j<=N;j++)
    {
        G+=gcd(i,j);
    }
思路:
設f[n] = gcd(1,n)+gcd(2,n)+gcd(3,n)+...+gcd(n-1,n);
s[n] = f[1]+f[2]+...+f[n];
則:s[n] = f[n]+s[n-1];

f[n]的約數個數一般少於n-1個。所以如果可以以約數歸類,就可以減少計算量。
設:gcd(n,i)表示 gcd(x,n) = i 時候的x的個數。(i為n的約數)
又:gcd(x,n)=i => gcd(x/i,n/i)=1;那么x/i的個數為(n/i)的歐拉函數值phi(n/i);
那么:f[n] = sum(i*phi(n/i)) (i為n的約數)
求每個f[n]不需要對每一個n單獨求約數。
可以利用素數篩法類似的做法來處理。

參考思路:lrj算法經訓練指南P125
*/

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 4e6+100;
ll f[maxn], s[maxn];
int phi[maxn];
void phiTable()
{
    for(int i = 1; i < maxn; i++) phi[i] = i;
    for(int i = 2; i < maxn; i+=2) phi[i]/=2;
    for(int i = 3; i < maxn; i+=2){
        if(phi[i]==i){
            for(int j = i; j < maxn; j+=i){
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }
}
void init()
{
    for(int i = 1; i < maxn; i++){
        for(int j = i*2; j < maxn; j+=i){
            f[j] += i*phi[j/i];
        }
    }
    for(int i = 2; i < maxn; i++) s[i] = s[i-1]+f[i];
}
int main()
{
    int T, cas=1, N;
    phiTable();
    init();
    while(scanf("%d",&N)==1&&N)
    {
        printf("%lld\n",s[N]);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM