1. 程式人生 > >51NOD1965:奇怪的式子

51NOD1965:奇怪的式子

http printf 常數 計算 min ets scanf turn span

傳送門
拆開變成
\[\prod_{i=1}^{n}\sigma_0(i)^{\mu(i)}\prod_{i=1}^{n}\sigma_0(i)^{i}\]
考慮 \(\prod_{i=1}^{n}\sigma_0(i)^{\mu(i)}\)
運用 \(\mu\) 的性質,設 \(c(i)\) 表示 \(i\) 的質數因子個數
那麽就是
\[\prod_{i=1}^{n}2^{\mu(i)c(i)}=2^{\sum_{i=1}^{n}\mu(i)c(i)}\]
只需要設
\(f(x,j)\) 表示 \(1\)\(x\) 最小質因子大於等於第 \(j\) 個質數的合數的 \(\mu(i)c(i)\)

的和
\(g(x,j)\) 表示 \(1\)\(x\) 最小質因子大於等於第 \(j\) 個質數的合數的 \(\mu(i)\) 的和
預處理出 \(cntp(i)\) 表示 \(1\)\(x\) 的質數個數就可以遞推了
這一部分直接 \(min25\) 篩即可
考慮 \(\prod_{i=1}^{n}\sigma_0(i)^{i}\)
分開考慮每個質數的貢獻
\(s(n,p,k)\) 表示 \(1\)\(n\) 中只含有 \(p^k\) 這個因子不含 \(p^i,i\ne k\) 的數的和
\(P\) 為質數集合
那麽
\[\prod_{i=1}^{n}\sigma_0(i)^{i}=\prod_{p\in P}\prod_{k=1}(k+1)^{s(n,p,k)}\]

\(Sum(x)=\sum_{i=1}^{x}i\)
那麽
\[s(n,p,k)=p^kSum(\lfloor\frac{n}{p^k}\rfloor)-p^{k+1}Sum(\lfloor\frac{n}{p^{k+1}}\rfloor)\]
\(p\le \sqrt{n}\) 的時候直接暴力計算
\(p > \sqrt{n}\) 的時候,顯然 \(k\) 最多就是 \(1\)
那麽
\[s(n,p,k)=pSum(\lfloor\frac{n}{p}\rfloor)\]
\(min25\) 篩預處理出 \(S(x)\) 表示 \(1\)\(x\) 的質數的和,然後數論分塊即可
註意常數優化QwQ

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

const ll mod(1e12 + 39);
const ll phi(1e12 + 38);
const int maxn(1e6 + 5);

inline ll Mul1(ll x, ll y) {
    register ll ret = x * y - (ll)((long double)x / mod * y + 0.5) * mod;
    return ret < 0 ? ret + mod : ret;
}

inline ll Mul2(ll x, ll y) {
    register ll ret = x * y - (ll)((long double)x / phi * y + 0.5) * phi;
    return ret < 0 ? ret + phi : ret;
}

inline ll Pow(ll x, ll y) {
    register ll ret = 1;
    for (; y; y >>= 1, x = Mul1(x, x))
        if (y & 1) ret = Mul1(ret, x);
    return ret;
}

inline void Inc1(ll &x, ll y) {
    x = x + y >= mod ? x + y - mod : x + y;
}

inline void Inc2(ll &x, ll y) {
    x = x + y >= phi ? x + y - phi : x + y;
}

inline ll Dec1(ll x, ll y) {
    return x - y < 0 ? x - y + mod : x - y;
}

inline ll Dec2(ll x, ll y) {
    return x - y < 0 ? x - y + phi : x - y;
}

int test, pr[maxn], tot, d, id1[maxn], id2[maxn], cnt;
ll n, val[maxn], cntp[maxn], f[maxn], g[maxn], s[maxn], sp[maxn];
bitset <maxn> ispr;

# define ID(x) ((x) <= d ? id1[x] : id2[n / (x)])

inline ll Sum1(ll x) {
    return (x & 1) ? Mul1(x, (x + 1) / 2) : Mul1(x / 2, x + 1);
}

inline ll Sum2(ll x) {
    return (x & 1) ? Mul2(x, (x + 1) / 2) : Mul2(x / 2, x + 1);
}

inline ll GetSum(ll x, ll v1, ll v2) {
    return Dec2(Mul2(v1, Sum2(x / v1)), Mul2(v2, Sum2(x / v2)));
}

inline void Solve() {
    while (cnt) f[cnt] = g[cnt] = 0, cnt--;
    register ll i, j, id, ans1, ans2, v, ret, lst, cur;
    for (d = sqrt(n), i = 1; i <= n; i = j + 1) {
        j = n / (n / i), val[++cnt] = n / i;
        val[cnt] <= d ? id1[val[cnt]] = cnt : id2[j] = cnt;
        cntp[cnt] = val[cnt] - 1, s[cnt] = Sum2(val[cnt]) - 1;
    }
    for (i = 1; i <= tot && pr[i] <= n / pr[i]; ++i)
        for (j = 1; j <= cnt && pr[i] <= val[j] / pr[i]; ++j) {
            id = ID(val[j] / pr[i]), cntp[j] -= cntp[id] - i + 1;
            Inc2(s[j], Mul2(pr[i], Dec2(sp[i - 1], s[id])));
        }
    for (--i; i; --i)
        for (j = 1; j <= cnt && pr[i] <= val[j] / pr[i]; ++j) {
            id = ID(val[j] / pr[i]);
            v = Dec2(cntp[id] - i, g[id]), Inc2(g[j], v);
            Inc2(v, cntp[id] - i), Inc2(f[j], Dec2(v, f[id]));
        }
    for (i = 1; i <= cnt; ++i) Inc2(f[i], phi - cntp[i]);
    ans1 = Pow(2, f[ID(n)]), ans2 = 1;
    for (i = 1; i <= tot && pr[i] <= n / pr[i]; ++i)
        for (j = 1, v = pr[i]; v <= n; v = v * pr[i], ++j) ans2 = Mul1(ans2, Pow(j + 1, GetSum(n, v, v * pr[i])));
    for (lst = sp[i - 1], ret = 0, i = pr[i]; i <= n; i = j + 1) {
        j = n / (n / i);
        Inc2(ret, Mul2(Dec2(cur = s[ID(j)], lst), Sum2(n / i))), lst = cur;
    }
    ans2 = Mul1(ans2, Pow(2, ret)), printf("%lld\n", Mul1(ans1, ans2));
}

int main() {
    register int i, j;
    ispr[1] = 1;
    for (i = 1; i < maxn; ++i) {
        if (!ispr[i]) pr[++tot] = i, sp[tot] = (sp[tot - 1] + i) % phi;
        for (j = 1; j <= tot && i * pr[j] < maxn; ++j) {
            ispr[i * pr[j]] = 1;
            if (!(i % pr[j])) break;
        }
    }
    scanf("%d", &test);
    while (test) scanf("%lld", &n), Solve(), --test;
    return 0;
}

51NOD1965:奇怪的式子