SP5971 LCMSUM - LCM Sum

SP5971 LCMSUM - LCM Sum

题意

  • \(\sum_{i=1}^nlcm(i,n)\).
  • 数据范围:\(T\leq 300000,n\leq 1000000\).

思路

首先知道\(lcm(i,n)=\frac{i*n}{gcd(i,n)}\),所以有原式:

\[n\sum_{i=1}^n\frac{i}{gcd(i,n)} \]

一般到这里都要枚举一下\(gcd(i,n)\)

\[n\sum_{d|n}\sum_{i=1}^n\frac{i}{d}[gcd(i,n)=d] \]

\(gcd(i,n)=d\),那么必然有\(i\)\(d\)的倍数。

所以枚举\(id\)

\[n\sum_{d|n}\sum_{i=1}^\frac{n}{d}i[gcd(i,n/d)=1]\\ \]

已知

\[\sum_{i=1}^ni[gcd(i,n)=1]=\frac{\varphi(n)*n}{2} \]

转换一下:

\[n\sum_{d|n}\frac{\varphi(\frac{n}{d})\frac{n}{d}}{2} \]

\(d\)\(\frac{n}{d}\)都是成对出现的,所以再改一下:

\[n\sum_{d|n}\frac{\varphi(d)d}{2} \]

这里由于询问特别大,不能每次都枚举约数。

所以用倍数法预处理出所有答案。

时间复杂度为n乘一个到n的调和级数求和,大概在\(nlnn\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int n;
int phi[maxn], primes[maxn], cnt;
ll ans[maxn];
bool vis[maxn];
void get_eulers(int n)
{
    phi[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            primes[++cnt] = i;
            phi[i] = i-1;
        }
        for(int j = 1; primes[j] <= n/i; j++)
        {
            vis[primes[j]*i] = 1;
            if(i % primes[j] == 0)
            {
                phi[primes[j]*i] = phi[i]*primes[j];
                break;
            }
            else phi[primes[j]*i] = phi[i]*(primes[j]-1);
        }
    }

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n/i; j++)
            ans[i*j] += 1ll*j*phi[j]/2;

    for(ll i = 1; i <= n; i++)
        ans[i] = ans[i]*i+i;
}

inline void solve()
{
    scanf("%d", &n);
    printf("%lld\n", ans[n]);
}

int main()
{
    get_eulers(maxn-5);
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}
posted @ 2020-02-07 07:15  zhaoxiaoyun  阅读(121)  评论(0编辑  收藏  举报