最大真因数(min_25筛)

Description:

一个合数的真因数是指这个数不包括其本身的所有因数,例如6 的正因数有
1; 2; 3; 6,其中真因数有1; 2; 3。一个合数的最大真因数则是这个数的所有真因数中最大
的一个,例如6 的最大真因数为3。
给定正整数l 和r,请你求出l 和r 之间(包括l 和r)所有合数的最大真因数之和。

题解:

考虑Min_25筛求质数和。

求g的过程中,有一个枚举最小质因子的过程,利用这个就可以求答案了。

#include
#include
#define ll long long
#define ul unsigned long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int N = 2e5 + 5;

ll l, r; ul w[N], sp[N], g[N], p[N];
int sqr, m, i1[N], i2[N], bz[N];

ll solve(ll n) {
    if(n <= 2) return 0;
    sqr = sqrt(n);
    fo(i, 2, sqr) bz[i] = 0; p[0] = 0; m = 0;
    fo(i, 2, sqr) {
        if(!bz[i]) p[++ p[0]] = i, sp[p[0]] = sp[p[0] - 1] + i;
        for(int j = 1; i * p[j] <= sqr; j ++) {
            bz[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i); w[++ m] = n / i;
        if(w[m] <= sqr) i1[w[m]] = m; else i2[n / w[m]] = m;
        g[m] = (w[m] + 2) * (w[m] - 1) / 2;
    }
    ul ans = 0;
    fo(j, 1, p[0]) for(int i = 1; i <= m && p[j] * p[j] <= w[i]; i ++) {
        int k = (w[i] / p[j] <= sqr) ? i1[w[i] / p[j]] : i2[n / (w[i] / p[j])];
        g[i] -= p[j] * (g[k] - sp[j - 1]);
        if(i == 1) ans += g[k] - sp[j - 1];
    }
    return ans;
}

int main() {
    freopen("factor.in", "r", stdin);
    freopen("factor.out", "w", stdout);
    while(scanf("%lld %lld", &l, &r) != EOF)
        printf("%lld\n", solve(r) - solve(l - 1));
}

你可能感兴趣的:(筛)