[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互素的所有自然数之和。有结论:

由于本人数学功底不好所以就不证明了。直接利用结论:预处理phi函数,对于n枚举因数即可。

代码

(不要随便看代码,不要随便看代码,不要随便看代码。因为很重要所以说三遍。)

#include 
#include 
#include 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(OI,-,Number,Theory)