UOJ188【UR #13】Sanrd (Min_25筛)

六眼飞鱼酱① 提交于 2020-02-19 04:34:51

这里
题意:说白了就是求这个i=1npsmax(i)\sum_{i=1}^{n}p_{smax}(i)
其中psmaxp_{smax}表示次小质因子,规定1和质数的次小质因子为0
做法:这道题是一道min25筛法的题,但不过不是普通的积性函数求和,需要对该算法有一定的理解。
首先我们还是以s(n,j)s(n,j)表示在1n1-n范围内最小质因子不小于pjp_j的和。
对于质数部分没有贡献为0,对于合数部分我们枚举最小质因子pjp_j的幂次,那么合数分为两部分,一部分pjkpl(l>j)pjkxp_{j}^{k}p_{l}(l>j),p_{j}^{k}x,这两部分中前一部分的答案为pjp_{j},后一部分的答案xx这个合数的答案,因此s(n,j)=k=jpe=1n(s(n/pjk,k+1)+pkx=pknisprime)s(n,j) = \sum_{k=j}^{|p|}\sum_{e=1}^{n} (s(n/p_{j}^{k},k+1)+p_{k}\sum_{x=p_{k}}^{n}isprime)
后面关于质数的计数部分,直接gg函数的处理即可。
听它们说还可以有另外一种写法就是强制第y层的质数为最大质因子,这样递推,我也没有这样写过,但不过估计比这个复杂。

#include "bits/stdc++.h"

using namespace std;
inline int read() {
    int x = 0;
    bool f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    if (f) return x;
    return 0 - x;
}
typedef long long ll;
const int maxn = 400010;
const ll mod = 1000000000 + 7;
ll quick(ll a, ll n, ll p) {
    ll ans = 1;
    for (; n; n >>= 1, a = a * a % p)
        if (n & 1) ans = ans * a % p;
    return ans;
}
int vis[maxn], sqr, cnt = 0;
ll suf1[maxn], suf2[maxn], inv2, inv6, n, pri[maxn];
void init(int lim) {
    vis[1] = 1;
    for (int i = 2; i <= lim; i++) {
        if (!vis[i]) {
            pri[++cnt] = i;
        }
        for (int j = 1; j <= cnt && i * pri[j] <= lim; j++) {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0) break;
        }
    }
}
int id1[maxn], id2[maxn], m = 0;
ll w[maxn << 1], g[maxn << 1], h[maxn << 1];
int getid(ll x) {
    if (x <= sqr) return id1[x];
    return id2[n / x];
}

void calc1() {
    for (ll l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        w[++m] = n / l;
        g[m] = w[m] - 1;
        if (w[m] <= sqr) id1[w[m]] = m;
        else id2[r] = m;
    }
    for (int j = 1; j <= cnt; j++) {
        for (int i = 1; i <= m && pri[j] * pri[j] <= w[i]; i++) {
            int k = getid(w[i] / pri[j]);
            g[i] -= g[k] - j + 1;
        }
    }
}

ll sum(ll x, int y) {
    if (x <= 1 || pri[y] > x) return 0;
    int k = getid(x);
    ll ret = 0;
    for (int i = y; i <= cnt && 1ll * pri[i] * pri[i] <= x; i++) {
        ll t1 = pri[i], t2 = 1ll * pri[i] * pri[i];
        for (int e = 1; t2 <= x; ++e, t1 = t2, t2 *= pri[i]) {
            ret += (sum(x / t1, i + 1) + 1ll * pri[i] * (g[getid(x / t1)] - i + 1));
        }
    }
    return ret;
}

int main() {
//    inv2 = quick(2, mod - 2, mod);
//    inv6 = quick(6, mod - 2, mod);
    ll l, r;
    cin >> l >> r;
    n = r;
    sqr = sqrt(n);
    init(sqr);
    calc1();
    ll ans = sum(n, 1);

    n = l - 1;
    sqr = sqrt(n);
    m = 0;
    calc1();
    ans = ans - sum(n, 1);
    cout << ans << endl;
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!