1. 程式人生 > 實用技巧 >BZOJ-2226 [Spoj 5971] LCMSum(尤拉函式的性質)

BZOJ-2226 [Spoj 5971] LCMSum(尤拉函式的性質)

題目描述

  計算:

\[\sum_{i=1}^{n}\text{lcm}(i,n) \]

  資料範圍:\(1\leq T\leq 3\times 10^5,1\leq n\leq 10^6\)

分析

\[\begin{aligned}&\sum_{i=1}^{n}\text{lcm}(i,n)\\=&\sum_{i=1}^{n}\frac{i·n}{\gcd(i,n)}\\=&n\sum_{i=1}^{n}\frac{i}{\gcd(i,n)}\\=&n\sum_{d\mid n}\sum_{i=1}^{n}\frac{i}{d}[\gcd(i,n)=d]\\\end{aligned} \]

  若 \(\gcd(i,n)=d\),則 \(i\) 肯定是 \(d\) 的倍數,設 \(i=i'd\),即:

\[\begin{aligned}&n\sum_{d\mid n}\sum_{i=1}^{n}\frac{i}{d}[\gcd(i,n)=d]\\=&n\sum_{d\mid n}\sum_{i'd=1}^{n}\frac{i'd}{d}[\gcd(i'd,n)=d]\\=&n\sum_{d\mid n}\sum_{i'=1}^{\lfloor\frac{n}{d}\rfloor}i'[\gcd(i',\frac{n}{d})=1]\\=&n\sum_{d\mid n}\sum_{i=1}^{d}i[\gcd(i,d)=1]\end{aligned} \]

  右邊的和式表示 \(1\) ~ \(d\) 中所有與 \(d\) 互質的數字之和,值為 \(\frac{d·\varphi(d)}{2}\)(當 \(d=1\) 時,值為 \(1\))。

  因此原式答案為:

\[n\sum_{d\mid n}\frac{d·\varphi(d)+[d=1]}{2} \]

  線性篩尤拉函式,列舉 \(d\),將 \(1\) ~ \(n\) 中所有 \(d\) 的倍數都加上 \(\frac{d·\varphi(d)}{2}\),時間複雜度 \(O(n\log n+T)\)

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
long long prime[N+10],phi[N+10],cnt,sum[N+10];
int vis[N+10];
void init()
{
    phi[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt&&i*prime[j]<=N;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(long long i=2;i<=N;i++)
        for(long long j=i;j<=N;j=j+i)
            sum[j]=sum[j]+i*phi[i]/2;
}
int main()
{
    init();
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        printf("%lld\n",n*(sum[n]+1));
    }
    return 0;
}