SPOJ - DIVCNT2 Counting Divisors (square)

 

求 $S_{2}(n)=\sum \limits_{i=1}^n \sigma_0(i^2)$

设 $f(n)=\sigma_0(n^2)$,$g(n)=2^{\omega(n)}$,$\omega(n)$ 表示 $n$ 唯一分解后有多少个不同的质因子。

那么 $f=g *1$,即 $f(n)=\sum\limits_{d|n}2^{\omega(d)}$,考虑约数 $d^2$ 除去 $d$ 中的一个质因子集合,那么就有 $2^{\omega(d)}$ 种选法,这样能得到 $n^2$ 的所有约数。

而 $g=\mu^2 * 1$,即 $2^{\omega(n)}=\sum\limits_{d|n}\mu^2(d)$,就是 $n$ 的无平方因子约数个数。

那么 $f=g*1=\mu^2*1*1=\mu^2*\sigma_0$

那么 $S_2(n)=\sum\limits_{i=1}^n\sum\limits_{d|n}\mu^2(d)\sigma_0(\frac{i}{d})=\sum\limits_{d=1}^n \mu^2(d)\sum \limits_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sigma_0(i)$
$s(n)=\sum\limits_{i=1}^n \mu^2(i)=\sum\limits_{i=1}^n \sum\limits_{d^2|i}\mu(d)=\sum\limits_{d=1}^{\sqrt n} \mu(d)\sum\limits_{i=1}^n[d^2 | i]=\sum\limits_{d=1}^{\sqrt n}\mu(d)\lfloor \frac{n}{d^2} \rfloor$,$O(\sqrt n)$ 解决。
$g(n)=\sum \limits_{i=1}^n \sigma_0(i)=\sum \limits_{d=1}^{n}\sum \limits_{d|i}1 = \sum \limits_{d=1}^{n}\lfloor \frac{n}{d} \rfloor$,$O(\sqrt n)$ 解决。

#include 
using ll = long long;

const int N = 1e8 + 7;
int XN;
int prime[N/10], prin;
short mu[N], mn[N];
int mu2[N];
ll thi[N];
ll Q[10007];

void init() {
    static bool vis[N];
    thi[1] = mu[1] = mu2[1] = 1;
    for (int i = 2; i <= XN; i++) {
        if (!vis[i]) {
            prime[++prin] = i;
            mu[i] = -1;
            thi[i] = mn[i] = 2;
        }
        for (int j = 1; j <= prin && 1LL * i * prime[j] <= XN; j++) {
            int v = i * prime[j];
            vis[v] = 1;
            if (i % prime[j] == 0) {
                mu[v] = 0;
                mn[v] = mn[i] + 1;
                thi[v] = thi[i] / mn[i] * mn[v];
                break;
            }
            mn[v] = 2;
            mu[v] = -mu[i];
            thi[v] = 2 * thi[i];
        }
    }
    for (int i = 1; i <= XN; i++)
        mu2[i] = mu[i] * mu[i] + mu2[i - 1], thi[i] += thi[i - 1];
}

std::unordered_map mpg, mps;

ll g(ll n) {
    if (n <= XN) return mu2[n];
    if (mpg.count(n)) return mpg[n];
    ll ans = 0;
    for (int i = 1, sqr = sqrt(n); i <= sqr; i++)
        ans += mu[i] * (n / (1LL * i * i));
    return mpg[n] = ans;
}

ll s(ll n) {
    if (n <= XN) return thi[n];
    if (mps.count(n)) return mps[n];
    ll ans = 0;
    for (ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        ans += (j - i + 1) * (n / i);
    }
    return mps[n] = ans;
}

int main() {
    int T;
    scanf("%d", &T);
    ll mx = 0;
    for (int i = 1; i <= T; i++)
        scanf("%lld", Q + i), mx = std::max(mx, Q[i]);
    XN = pow(mx, 2. / 3.);
    if (XN >= 1e6 && XN <= 1e8 + 1)
        XN = 1e8;
    init();
    for (int t = 1; t <= T; t++) {
        ll n = Q[t];
        ll ans = 0;
        for (ll i = 1, j; i <= n; i = j + 1) {
            j = n / (n / i);
            ans += s(n / i) * (g(j) - g(i - 1));
        }
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

你可能感兴趣的:(SPOJ - DIVCNT2 Counting Divisors (square))