MIN 25筛(简单的函数)

MIN25筛的瞎扯:

在复杂度 O ( n 3 4 / l o g n ) O(n^{\frac{3}{4}}/logn) 下解决一些积性函数的和
做一些规定:
p r i m e ( i ) : i 0 prime(i):i为质数时,为一,否则为0
p k : p_k: 表示第 k k 个质数,规定第零个质数为1;
m i n p ( 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]
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]
p p 都是指质数
目的:求 i = 1 n f ( i ) \sum\limits_{i=1}^nf(i)
要求
f ( i ) f(i) 是一个积性函数(即, a , b a,b 互质时, f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) )
f ( p k ) f(p^k) 可以快速求
f ( p ) f(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
因为只要分别求出 p k p^k 的前 n n 项和,再与系数相乘,再把各项加起来就行
所以令 f ( p ) f(p) = p k p^k
我们把问题简化为两部分来

第一部分

求解 i = 1 n [ p r i m e ( i ) ] f ( i ) \sum\limits_{i=1}^{n}[prime(i)]f(i)
因为一个合数 a a 的最小质因子不大于 a \sqrt{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|) ,这里的|p|表示不大于 n n 的最大质数。
显然 g ( n , 0 ) = i = 1 n f ( i ) g(n,0)=\sum\limits_{i=1}^{n}f(i)
现在来考虑怎么 g ( n , j 1 ) g ( n , j ) g(n,j-1)转移到g(n,j)
g ( n , j 1 ) g ( n , j ) g(n,j-1)转到g(n,j) 会少掉一些合数的最小质因子是 p j p_j 的,所以要减掉。
p j p j > n p_j\cdot p_j>n 则不存在这样的合数
此时有 g ( n , j ) = g ( n , j 1 ) g(n,j)=g(n,j-1)
那么 p j p j < = n p_j\cdot p_j<=n p j < n p j p_j<\frac{n}{p_j}
所以 g ( n p j , j 1 ) g(\frac{n}{p_j},j-1) 包含了小于 p j p_j 的质数和大于 p j p_j 且其最小质因子大于等于 p j p_j 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) 包含了最小质因子大于等于 p j p_j 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)

第二部分

求解 S ( n , 1 ) S(n,1) 则答案为 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1)
易知 S ( n , m ) = 0 S(n,m)=0 , p m p_m 为大于 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})
可以看到我们需要的 g g 点有 n , n / 2 , n / 3 1 n,n/2,n/3\cdots 1 一共 n \sqrt{n} 个点,所以需要一些分块

例题:简单的函数

#include<bits/stdc++.h>
#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;
    }
}

发布了105 篇原创文章 · 获赞 30 · 访问量 5590

猜你喜欢

转载自blog.csdn.net/weixin_43965698/article/details/104350892