BZOJ 4176. Lucas的数论

 

求 $$\sum_{i=1}^n\sum_{j=1}^md(ij)$$
$$d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)=1]=\sum_{x|i}\sum_{y|j}\sum_{p|(x,y)}\mu(p)$$
$$=\sum_p \mu(p)\sum_{x|i}[d|x]\sum_{y|j}[d|y]=\sum_{p|i,p|j}\mu(p)d(\frac{i}{p})d(\frac{j}{p})$$
代回原式得
$$\sum_{i=1}^n\sum_{j=1}^m\sum_{p|i,p|j}\mu(p)d(\frac{i}{p})d(\frac{j}{p})=\sum_{p}\mu(p)\sum_{p|i}d(\frac{i}{p})\sum_{p|j}d(\frac{j}{p})$$
$$=\sum_{p}\mu(p)\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}d(i)\sum_{j=1}^{\lfloor \frac{m}{p} \rfloor}d(j)$$
令 $s(n)=\sum_{i=1}^n d(i)=\sum_{i=1}^n\sum_{d=1}^i[d|i]=\sum_{d=1}^n \lfloor \dfrac{n}{d} \rfloor$
原式为$$\sum_{p}\mu(p)s(\lfloor \frac{n}{p} \rfloor)s(\lfloor \frac{m}{p} \rfloor)$$

$\mu$ 的前缀和用杜教筛,$s$ 的前缀和用整除分块

#include <bits/stdc++.h>

const int N = 5e4 + 7;
const int MOD = 1000000007;
int mu[N], prime[N], prin, d[N], t[N];
bool vis[N];

inline void M(int &ans) {
    if (ans >= MOD) ans -= MOD;
    if (ans < 0) ans += MOD;
}

void init(int n) {
    mu[1] = d[1] = t[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            prime[++prin] = i;
            d[i] = 2;
            t[i] = 1;
            mu[i] = -1;
        }
        for (int j = 1; j <= prin && i * prime[j] < N; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                t[i * prime[j]] = t[i] + 1;
                mu[i * prime[j]] = 0;
                d[i * prime[j]] = d[i] / (t[i] + 1) * (t[i] + 2);
                break;
            }
            d[i * prime[j]] = d[i] * 2;
            t[i * prime[j]] = 1;
            mu[i * prime[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= n; i++)
        M(mu[i] += mu[i - 1]), M(d[i] += d[i - 1]);
}

std::unordered_map<int, int> muu, dd;


inline int Mu(int n) {
    if (n < N) return mu[n];
    if (muu.count(n)) return muu[n];
    int ans = 1;
    for (int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        M(ans -= 1LL * (j - i + 1) * Mu(n / i) % MOD);
    }
    return muu[n] = ans;
}

inline int D(int n) {
    if (n < N) return d[n];
    if (dd.count(n)) return dd[n];
    int ans = 0;
    for (int i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        M(ans += 1LL * (j - i + 1) * (n / i) % MOD);
    }
    return dd[n] = ans;
}

int solve(int n) {
    int ans = 0;
    for (int i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        M(ans += 1LL * (Mu(j) - Mu(i - 1) + MOD) * D(n / i) % MOD * D(n / i) % MOD);
    }
    return ans;
}

int main() {
    init(N - 1);
    int n;
    scanf("%d", &n);
    printf("%d\n", solve(n));
    return 0;
}
View Code

 

posted @ 2020-02-02 23:48  Mrzdtz220  阅读(115)  评论(0编辑  收藏  举报