MIN 25筛(简单的函数)

MIN25筛的瞎扯:

在复杂度 O ( n 3 4 / l o g n ) O(n^{\frac{3}{4}}/logn) O(n43/logn)下解决一些积性函数的和
做一些规定:
p r i m e ( i ) : i 为 质 数 时 , 为 一 , 否 则 为 0 prime(i):i为质数时,为一,否则为0 prime(i):i0
p k : p_k: pk:表示第 k k k个质数,规定第零个质数为1;
m i n p ( i ) : 表 示 i 的 最 小 质 因 子 minp(i):表示i的最小质因子 minp(i):i
g ( n , j ) = ∑ i = 1 n [ p r i m e ( i ) o r ( m i n p ( i ) > p j ) ] f [ i ] g(n,j)=\sum\limits_{i=1}^{n}[prime(i)or(minp(i)>p_j)]f[i] g(n,j)=i=1n[prime(i)or(minp(i)>pj)]f[i]
S ( n , j ) = ∑ i = 1 n [ m i n p ( i ) > = p j ] f [ i ] S(n,j)=\sum\limits_{i=1}^{n}[minp(i)>=p_j]f[i] S(n,j)=i=1n[minp(i)>=pj]f[i]
p p p都是指质数
目的:求 ∑ i = 1 n f ( i ) \sum\limits_{i=1}^nf(i) i=1nf(i)
要求
f ( i ) f(i) f(i)是一个积性函数(即, a , b a,b a,b互质时, f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b))
f ( p k ) f(p^k) f(pk)可以快速求
f ( p ) f(p) f(p)是一个是一个关于 p p p的项数较少的多项式,或可以快速求值
f ( p ) = c 1 p k 1 + c 2 p k 2 + ⋯ f(p)=c_1p^{k_1}+c_2p^{k_2}+\cdots f(p)=c1pk1+c2pk2+
因为只要分别求出 p k p^k pk的前 n n n项和,再与系数相乘,再把各项加起来就行
所以令 f ( p ) f(p) f(p)= p k p^k pk
我们把问题简化为两部分来

第一部分

求解 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) \sum\limits_{i=1}^{n}[prime(i)]f(i) i=1n[prime(i)]f(i)
因为一个合数 a a a的最小质因子不大于 a \sqrt{a} a
所以 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) = g ( n , ∣ p ∣ ) \sum\limits_{i=1}^{n}[prime(i)]f(i)=g(n,|p|) i=1n[prime(i)]f(i)=g(n,p),这里的|p|表示不大于 n n n的最大质数。
显然 g ( n , 0 ) = ∑ i = 2 n f ( i ) g(n,0)=\sum\limits_{i=2}^{n}f(i) g(n,0)=i=2nf(i)
这一部分怎么办,我们最终要得到的是 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) \sum\limits_{i=1}^{n}[prime(i)]f(i) i=1n[prime(i)]f(i)所以我们在一部分假设对于任意 i i i,都有 f ( i ) = i k f(i)=i^k f(i)=ik,最后得到的是质数的 f f f值,所以并不会影响结果
现在来考虑怎么 g ( n , j − 1 ) 转 移 到 g ( n , j ) g(n,j-1)转移到g(n,j) g(n,j1)g(n,j)
g ( n , j − 1 ) 转 到 g ( n , j ) g(n,j-1)转到g(n,j) g(n,j1)g(n,j)会少掉一些合数的最小质因子是 p j p_j pj的,所以要减掉。
p j ⋅ p j > n p_j\cdot p_j>n pjpj>n则不存在这样的合数
此时有 g ( n , j ) = g ( n , j − 1 ) g(n,j)=g(n,j-1) g(n,j)=g(n,j1)
那么 p j ⋅ p j < = n p_j\cdot p_j<=n pjpj<=n p j < n p j p_j<\frac{n}{p_j} pj<pjn
所以 g ( n p j , j − 1 ) g(\frac{n}{p_j},j-1) g(pjn,j1)包含了小于 p j p_j pj的质数和大于 p j p_j pj且其最小质因子大于等于 p j p_j pj f f f
所以 g ( n p j , j − 1 ) − g ( p j , j − 1 ) g(\frac{n}{p_j},j-1)-g(p_j,j-1) g(pjn,j1)g(pj,j1)包含了最小质因子大于等于 p j p_j pj f f f值。
所以有 g ( n , j ) = g ( n , j − 1 ) − f ( p j ) ( g ( n p j − g ( p j , j − 1 ) g(n,j)=g(n,j-1)-f(p_j)(g(\frac{n}{p_j}-g(p_j,j-1) g(n,j)=g(n,j1)f(pj)(g(pjng(pj,j1)

第二部分

求解 S ( n , 1 ) S(n,1) S(n,1) 则答案为 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1)
易知 S ( n , m ) = 0 S(n,m)=0 S(n,m)=0, p m p_m pm为大于 n n n的质数
第二部分其实道理跟第一部分一样的,自己推导一下就行。
结果:
S ( n , j ) = g ( n , ∣ p ∣ ) − ∑ i = 1 j − 1 + ∑ k = j p k 2 < = n ∑ e = 1 p k e + 1 < = n S ( n p k e , k + 1 ) f ( p k ) + f ( p k + 1 ) S(n,j)=g(n,|p|)-\sum\limits_{i=1}^{j-1}+\sum\limits_{k=j}^{p_k^2<=n}\sum\limits_{e=1}^{p_k^{e+1}<=n}S(\frac{n}{p_k^e},k+1)f(p_k)+f(p_{k+1}) S(n,j)=g(n,p)i=1j1+k=jpk2<=ne=1pke+1<=nS(pken,k+1)f(pk)+f(pk+1)
可以看到我们需要的 g g g点有 n , n / 2 , n / 3 ⋯ 1 n,n/2,n/3\cdots 1 n,n/2,n/31一共 n \sqrt{n} n 个点,所以需要一些分块

例题:简单的函数

#include
#define ll long long
#define ull unsiged ll
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, r, l) for (int i = r; i >= l; i--)
#define boots   ios::sync_with_stdio(0);     cin.tie(0)
#define endl '\n'
#define mod 1000000007
#define inf 0x3f3f3f3f
#define lnf LLONG_MAX
#define si(n) scanf("%d", &n)
#define sl(n) scanf("%lld", &n)
#define pf(n) printf("%lld\n", n)
#define sz size
using namespace std;
//const db pi = 3.1415926535898;
const int N = 2e5 + 10;
const int INV2 = 500000004;
int top;
unordered_map<ll, ll> mp;
int pri[N], ji[N];
ll g[N], h[N], pris[N];
ll w[N];
//pri[i]表示第几个质数,pris[i]表示前i个质数的和
void init(ll MX) {
    memset(ji, 0, sizeof(ji));
    pris[0] = 0;
    top = 0;
    for (int i = 2; i <= MX; i++) {
        if (!ji[i]) {
            pri[++top] = i;
            pris[top] = (pris[top - 1] + i) % mod;
        }
        for (int j = 1; j <= top && 1ll * i * pri[j] <= MX; j++) {
            int cur = i * pri[j];
            ji[cur] = 1;
            if (i % pri[j] == 0)
                break;
        }
    }
}
void add(ll &a, ll b) {
    a = (a + b) % mod;
    if (a < 0)
        a += mod;
    return;
}
ll S(ll n, ll m) {
    if (n <= 1 || pri[m] > n)
        return 0;
    ll kt = mp[n];
    ll res = (g[kt] - h[kt] - (pris[m - 1] - m + 1)) % mod;
    if (res < 0)
        res += mod;
    if (m == 1)
        res += 2;
    for (int k = m; k <= top && 1ll * pri[k] * pri[k] <= n; k++) {
        ll ans = pri[k];
        for (int i = 1; ans * pri[k] <= n; i++, ans *= pri[k]) {
            add(res, (1ll * (S(n / ans, k + 1)) * (pri[k] ^ i) % mod + (pri[k] ^ (i + 1))) % mod);
        }
    }
    return res;
}
int main() {
    ll n;
    while (cin >> n) {
        ll fb = sqrt(n);
        init(fb);
        ll j;
        int times = 0;
        ll ans;

        for (ll i = 1; i <= n; i = j + 1) {
            w[++times] = n / i;
            j = n / (n / i);
            h[times] = (w[times] - 1) % mod;
            g[times] = (((w[times] % mod * (w[times] + 1) % mod) % mod * INV2) % mod - 1 + mod) % mod;
            mp[w[times]] = times;
        }
        for (int i = 1; i <= top; i++) {
            ll k = 1ll * pri[i] * pri[i];
            for (int j = 1; j <= times && k <= w[j]; j++) {
                int kt = mp[w[j] / pri[i]];
                add(g[j], mod - 1ll * pri[i] * (g[kt] - pris[i - 1]) % mod);
                add(h[j], mod - (h[kt] - i + 1) % mod);
            }
        }
        //g[i]-h[i]=w[i]以内
        //w[i]表示n/i,mp[n/i]=i,h[i]表示n/i(含)内有多少个质数,g[i]=n/i内的质数之和表示
        cout << (S(n, 1) + 1) % mod << endl;
    }
}

你可能感兴趣的:(数学)