[BZOJ2226][Spoj5971][數論]LCMSum[好題]

題幹

T組詢問,每組給出一個n,求:

1inlcm(i,n),(1T300000,1n1000000)

題解

先進行變形:

1inlcm(i,n)=1ini×ngcd(i,n)

枚舉gcd(i, n),有:
1ini×ngcd(i,n)=n×d|n1inid×[gcd(i,n)=d]=n×d|n1jndj×[gcd(j,nd)=1],(j=id)

顯然d與n/d是等價的,於是:
1inlcm(i,n)=n×d|n1ini×[gcd(i,d)=1]

即我們要求小於i且與i互素的所有自然數之和。有結論:

V

由於本人數學功底不好所以就不證明了。直接利用結論:預處理phi函數,對於n枚舉因數即可。

代碼

(不要隨便看代碼,不要隨便看代碼,不要隨便看代碼。因爲很重要所以說三遍。)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

//Global Variables & Definitions
#define LL long long
#define MAXN 1000010
int T, _n;
//End Global Variables & Definitions

//Number Theory
int p[MAXN];
int vis[MAXN];
int ph[MAXN];
int pcnt = 0;

void init_p() {
    ph[1] = 1; ph[2] = 1;

    LL temp;
    for(int i = 2;i < MAXN;++i) {
        if(!vis[i]) { p[pcnt] = i; ph[i] = i - 1; ++pcnt; }

        for(int j = 0;j < pcnt && (temp = (LL)p[j] * i) < MAXN;++j) {
            vis[temp] = 1;

            if(i % p[j] == 0) { ph[temp] = ph[i] * p[j]; break; }
            else ph[temp] = ph[i] * (p[j] - 1);
        }
    }

    //for(int i = 1;i <= 20;++i) printf("phi[%d] = %d\n", i, ph[i]);
}

inline LL phi(int n) {
    return ph[n];
}

LL solve(int n) {
    LL ans = 0ll;   
    int half = (int) (sqrt(n) + 0.01);

    if(half * half == n) { ans += phi(half) * half / 2; --half; }
    ans += 1; //for 1
    ans += phi(n) * n / 2;
    for(int i = 2;i <= half;++i)
        if(n % i == 0) {
            ans += phi(i) * i / 2;
            ans += phi(n / i) * n / i / 2;
        }

    return ans * n;
}
//End Number Theory

//Main Structure
inline void ir() {
    scanf("%d", &T);
    init_p();
}

int main() {
    ir();

    while(T--) {
        scanf("%d", &_n);
        printf("%lld\n", solve(_n));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章