洛谷 - P1891 - 疯狂LCM - 线性筛

另一道数据范围不一样的题:https://www.cnblogs.com/Yinku/p/10987912.html


$F(n)=\sum\limits_{i=1}^{n} lcm(i,n) $
$\sum\limits_{i=1}^{n} \frac{in}{gcd(i,n)} $

枚举g,提n。
$n \sum\limits_{g|n}\frac{1}{g} \sum\limits_{i=1}^{n} i [gcd(i,n)==g] $

前面带有id的时候,除以g要提g到前面。
$n \sum\limits_{g|n} \sum\limits_{i=1}^{\frac{n}{g}} i [gcd(i,\frac{n}{g})1] $
$n \sum\limits_{g|n} \sum\limits_{i=1}^{\frac{n}{g}} i [gcd(i,\frac{n}{g})
1] $

考虑子问题:
$H(n)=\sum\limits_{i=1}^{n} i [gcd(i,n)==1] $

显然为(所有的i的和减去是n的因子d的倍数的数,容斥一下带个莫比乌斯函数)
$\sum\limits_{i=1}^{n}i + \sum\limits_{d|n,d>=2} \mu(d) (d+2d+...+n) $

吸收,整理。
$\frac{1}{2} \sum\limits_{d|n} \mu(d) (d+n)(\frac{n}{d}) $

提n,分配律。
$\frac{n}{2} \sum\limits_{d|n} \mu(d) (d+n)(\frac{1}{d}) \( \)\frac{n}{2} \sum\limits_{d|n} \mu(d) (1+\frac{n}{d}) \( \)\frac{n}{2} (\sum\limits_{d|n} \mu(d) +\sum\limits_{d|n} \mu(d)\frac{n}{d}) $

使用莫比乌斯函数的性质:
$\frac{n}{2} ([n==1] +\varphi(n)) $

所以:
$H(n)=\sum\limits_{i=1}^{n} i [gcd(i,n)1] = \frac{n}{2} ([n1] +\varphi(n)) $

原式:
\(F(n)=n \sum\limits_{g|n}H(\frac{n}{g}) = \frac{n}{2}\sum\limits_{g|n}\frac{n}{g} ([\frac{n}{g}==1] +\varphi(\frac{n}{g}))\)

分配律:
\(\frac{n}{2}(\sum\limits_{g|n}\frac{n}{g} [\frac{n}{g}==1] + \sum\limits_{g|n}\frac{n}{g} \varphi(\frac{n}{g}) )\)

很显然可以把 \(\frac{n}{g}\) 换成 \(g\)
\(\frac{n}{2}(\sum\limits_{g|n} g [g==1] + \sum\limits_{g|n} g \varphi(g) )\)

结论:
\(F(n)=\sum\limits_{i=1}^{n} lcm(i,n) = \frac{n}{2}(1 + \sum\limits_{g|n} g \varphi(g) )\)

后面明显是积性函数,可以用线性筛(本题n数据范围较小,否则可以直接质因数分解卡过去)。问题在于在质数幂次位置怎么求。列一下就可以发现怎么求。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline int read() {
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    do {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    } while(c>='0'&&c<='9');
    return x;
}

inline void write(ll x) {
    if(x>9) {
        write(x/10);
    }
    putchar(x%10+'0');
    return;
}

const int MAXN=1e6;

int pri[MAXN+1];
int &pritop=pri[0];
ll q[MAXN+1];
int pk[MAXN+1];

void sieve(int n=MAXN) {
    pk[1]=1;
    q[1]=1;
    for(int i=2; i<=n; i++) {
        if(!pri[i]) {
            pri[++pritop]=i;
            pk[i]=i;
            q[i]=1ll*i*(i-1)+1;
        }
        for(int j=1; j<=pritop; j++) {
            int &p=pri[j];
            int t=i*p;
            if(t>n)
                break;
            pri[t]=1;
            if(i%p) {
                pk[t]=pk[p];
                q[t]=q[i]*q[p];
            }
            else{
                pk[t]=pk[i]*p;
                if(pk[t]==t){
                    q[t]=q[i]+1ll*(t-t/p)*t;
                }else{
                    q[t]=q[pk[t]]*q[t/pk[t]];
                }
                break;
            }
        }
    }
}

inline ll ans(int n){
    ll res=q[n]+1;
    res*=n;
    res/=2;
    return res;
}

inline void solve() {
    sieve();
    int t=read();
    while(t--){
        int n=read();
        write(ans(n));
        putchar('\n');
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    solve();
    return 0;
}
posted @ 2019-06-10 15:19  韵意  阅读(211)  评论(0编辑  收藏  举报