【51Nod 1363】最小公倍数之和

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1363
\[ \begin{aligned} &\sum_{i=1}^n\frac{in}{(i,j)}\\ =&n\sum_{d|n}\sum_{i=1}^{\frac nd}\left[\left(i,\frac nd\right)=1\right]i\\ =&n\left(1+\sum_{d|n,d\neq n}\sum_{i=1}^{\left\lfloor\frac {n}{2d}\right\rfloor}\left[\left(i,\frac nd\right)=1\right]\right)\\ =&n+\frac n2\sum_{d|n,d\neq 1}d\varphi(d) \end{aligned} \]
重点是统计\(\sum\limits_{d|n,d\neq 1}d\varphi(d)\)
\[ \begin{aligned} &\sum_{d|n,d\neq 1}d\varphi(d)\\ =&\prod\sum_{j=0}^{c_i}p_i^j\times\varphi\left(p_i^j\right)-1\\ =&\prod\left(1+\sum_{j=1}^{c_i}p_i^{2j-1}\left(p_i-1\right)\right)-1\\ =&\prod\left(1+\frac{p_i^{2c_i+1}-p_i}{p_i+1}\right)-1 \end{aligned} \]
质因子分解统计就可以了,时间复杂度\(O\left(T\sqrt n\right)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

const int N = 100000;
const int p = 1000000007;

bool notp[N + 3];
int T, n, prime[N + 3], num = 0, ni[N + 3];

void Euler_shai() {
    for (int i = 2; i <= N; ++i) {
        if (!notp[i]) prime[++num] = i;
        for (int j = 1; j <= num && prime[j] * i <= N; ++j) {
            notp[prime[j] * i] = true;
            if (i % prime[j] == 0) break;
        }
    }
    ni[1] = 1;
    for (int i = 2; i <= N; ++i)
        ni[i] = 1ll * (p - p / i) * ni[p % i] % p;
}

int ipow(int a, int b) {
    int r = 1, w = a;
    while (b) {
        if (b & 1) r = 1ll * r * w % p;
        w = 1ll * w * w % p;
        b >>= 1;
    }
    return r;
}

int cal(int x) {
    int ret = 1, ci;
    for (int i = 1, pi = 2; i <= num && pi * pi <= x; pi = prime[++i]) {
        if (x % pi == 0) {
            ci = 1; x /= pi;
            while (x % pi == 0) x /= pi, ++ci;
            ret = 1ll * ret * (1ll * (ipow(pi, 2 * ci + 1) - pi + p) % p * ni[pi + 1] % p + 1) % p;
        }
    }
    if (x > 1) {
        ret = 1ll * ret * ((1ll * x * x % p * x % p - x + p) % p * ipow(x + 1, p - 2) % p + 1) % p;
    }
    return ret;
}

int main() {
    Euler_shai();
    
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        printf("%lld\n", (1ll * n * ni[2] % p * (cal(n) - 1) % p + n) % p);
    }
    return 0;
}

转载于:https://www.cnblogs.com/abclzr/p/6763347.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值