SP5971 LCMSUM

SP5971 LCMSUM - LCM Sum

题意

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

思路

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

[nsum_{i=1}^nfrac{i}{gcd(i,n)} ]

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

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

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

所以枚举(id)

[nsum_{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} ]

转换一下:

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

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

[nsum_{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
", ans[n]);
}

int main()
{
    get_eulers(maxn-5);
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}
原文地址:https://www.cnblogs.com/zxytxdy/p/12271856.html