疯狂 LCM

疯狂LCM luoguP1891
本题题目比较简单,是莫比乌斯反演的好题。

题目要求
\(\sum\limits_{i=1}^n\operatorname{lcm}(i,n)\)

开始推式子

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

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

\[=\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}\varepsilon(\gcd(i,\frac{n}{d}))ni\ \ [ps:\varepsilon(x)=[x==1]] \]

\[=\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}\sum_{f|\gcd(i,\frac{n}{d})}\mu(f)ni[Möbius\ inversion\ formula] \]

\[=n\sum_{d|n}\sum_{f|\frac{n}{d}}\mu(f)f\sum_{i=1}^{\frac{n}{df}}i \]

\(F(x)=\sum\limits_{i|x}\mu(i)i\sum\limits_{j=1}^{\frac{x}{i}}i\)

原式\(=n\sum\limits_{d|n}F(\frac{n}{d})\)

所以筛 $ 2 $ 次,第一遍筛出\(F(x)\),第二次筛出所求值(后需\(*n\)

时间复杂度\(O(n\log_2n)\),证明见无穷级数相关
\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.}\)

#include<map>
#include<cmath>
#include<stack>
#include<deque>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
# define Type template<typename T>
# define ll long long
# define read read1<ll>()
Type T read1(){
    T t=0;char k;
    bool v=0;
    do (k=getchar())=='-'&&(v=1);while('0'>k||k>'9');
    while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
    return v?-t:t;
}
# define mod 20101009
int u[1000005],pr[1000005];
bool vis[1000005];
ll v[1000005],va[1000005];
ll Get(ll x,ll y){return x*(x+1)/2%mod*(y*(y+1)/2%mod)%mod;}
void init(int N=1000000){
    u[1]=1;
    for(int i=2;i<=N;++i){
        if(!vis[i]){
            pr[++pr[0]]=i;
            u[i]=-1;
        }
        for(int j=1;j<=pr[0]&&pr[j]*i<=N;++j){
            vis[i*pr[j]]=1;
            if(!(i%pr[j]))break;
            u[i*pr[j]]=-u[i];
        }
    }
    for(int i=1;i<=N;++i)
        for(int j=1;j*i<=N;++j)
            v[i*j]+=1ll*u[i]*i*j*(j+1)>>1;
    for(int i=1;i<=N;++i)
        for(int j=i;j<=N;j+=i)
            va[j]+=v[j/i];
}
int main(){
    init();
    for(int T=read;T--;){
        int x=read;
        printf("%lld\n",va[x]*x);
    }
    return 0;
}
posted @ 2020-08-26 18:53  ファイナル  阅读(126)  评论(0)    收藏  举报