final-数论(积性函数、线性筛、杜教筛、莫比乌斯反演)

数论分块: ⌊ n i ⌋ \lfloor \frac n i \rfloor in最多只有 2 ⋅ ⌊ n ⌋ 2 · \lfloor \sqrt n \rfloor 2n 个取值。

for(ll l = 1, r; l <= n; l = r + 1) {
    r = n / (n / l);
    res -= (r - l + 1) * S(n / l);
}

常见的积性函数:
φ(n) -欧拉函数
μ(n) -莫比乌斯函数,关于非平方数的质因子数目
gcd(n,k) -最大公因子,当k固定的情况
d(n) -n的正因子数目
σ(n) -n的所有正因子之和
1(n) -不变的函数,定义为 1(n) = 1 (完全积性)
Id(n) -单位函数,定义为 Id(n) = n(完全积性)
Idk(n) -幂函数,对于任何复数、实数k,定义为Idk(n) = n^k (完全积性)
ε(n) -定义为:若n = 1,ε(n)=1;若 n > 1,ε(n)=0。别称为“对于狄利克雷卷积的乘法单位”(完全积性)
欧拉函数:
通俗定义:欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)
重要性质: ∑ d ∣ n ϕ ( d ) = n \sum_{d|n}\phi(d) = n dnϕ(d)=n
欧拉函数表:1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16, 24, 12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, 60, 30, 36, 32, 48, 20, 66, 32, 44
(O(\sqrt n))求欧拉函数:

ll euler(ll x)
{
    ll res = x;
    for(ll i = 2; i * i <= x; ++i){
        if(x % i == 0){
             res = res / i * (i - 1);
             while(x % i == 0) x /= i;
         }
    }
    if(x > 1) res = res / x * (x - 1);
    return res;
}

莫比乌斯函数:
如果一个数包含平方因子,那么miu(n) = 0。例如:miu(4), miu(12), miu(18) = 0
如果一个数不包含平方因子,并且有k个不同的质因子,那么miu(n) = (-1)^k
通俗定义:μ(1) = 1。若i有平方因子,则μ(i) = 0。否则μ(i) = (-1)^k,k为i的质因数分解中质数的个数。
重要性质: ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d) = [n = 1] dnμ(d)=[n=1]
莫比乌斯函数表: 1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0, 1, 1, -1, 0, 0, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 0, -1, -1, -1, 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, -1, 1, 0, 0, 1, -1
(O(\sqrt n))求莫比乌斯函数:

int mobius(ll x)
{
    int cnt = 0;
    for (ll i = 2; i * i <= x; ++i){
        if (x % i == 0) ++cnt, x /= i;
        if (x % i == 0) return 0;
    }
    if (x != 1) ++cnt;
    return cnt & 1 ? -1 : 1;
}

迪利克雷卷积(Dirichlet product):
( f ∗ g ) ( i ) = ∑ d ∣ n f ( d ) ⋅ g ( n d ) (f * g)(i) = \sum_{d|n}f(d)·g(\frac n d) (fg)(i)=dnf(d)g(dn)
迪利克雷卷积推杜教筛:s://.luogu.org/problemnew/solution/P4213
杜教筛:

const int maxn = 2e6 + 5;

ll prime[maxn], mu[maxn], phi[maxn], sieve[maxn], mem[maxn], cons;
//线性筛
void init()
{
    prime[1] = phi[1] = mu[1] = 1;
    int cnt = 0;
    for (int i = 2; i < maxn; ++i){
        if (!prime[i]) phi[i] = i - 1, mu[i] = -1, sieve[++cnt] = i;
        for (int j = 1; j <= cnt && i * sieve[j] < maxn; ++j){
            prime[i * sieve[j]] = 1;
            if (i % sieve[j] == 0){
                phi[i * sieve[j]] = phi[i] * sieve[j];
                mu[i * sieve[j]] = 0;
                break;
            }else{
                phi[i * sieve[j]] = phi[i] * (sieve[j] - 1);
                mu[i * sieve[j]] = -mu[i];
            }
        }
    }
    for (int i = 2; i < maxn; ++i){
        phi[i] += phi[i - 1];
        phi[i] %= mod;
        mu[i] += mu[i - 1];
    }
    return ;
}
//杜教筛
inline ll S(ll n)
{
    if (n <= maxn) return phi[n];
    if (mem[cons / n] != INF) return mem[cons / n];
    //这里是求欧拉函数和,求莫比乌斯函数和把res初始化成1就好了。
    ll res = (n % mod) * ((n + 1) % mod) / 2 % mod;
    for(ll l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res -= (r - l + 1) * S(n / l);
    }
    res %= mod; res += mod; res %= mod;
    return mem[cons / n] = res;
}
ll cal(ll x)
{
    cons = x;
    memset(mem, 0x3f, sizeof(mem));
    return S(x);
}
int main()
{
    init();
    ll a;
    scanf("%lld",&a);
    printf("%lld\n",cal(a));
    return 0;
}

杜教筛的另一种写法,用map,多个log,但是不用清零,多组数据的时候更快。
😕/acm.hdu.edu.cn/showproblem.php?pid=6706

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

const int mod = 1e9 + 7, inf = 0x3f3f3f3f;
ll quickpow(ll x, ll k)
{
    ll res = 1;
    while(k){
        if(k & 1) res = (res * x) % mod;
        k >>= 1, x = (x * x) % mod;
    }
    return res;
}
const int maxn = 2e6;
unordered_map<ll,ll> mii;
ll inv2, inv6;
ll sum1(ll l, ll r)
{
    return (l + r) * (r - l + 1) / 2 % mod;
}
ll sum2(ll x)
{
    return x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}
ll prime[maxn + 10], phi[maxn + 10], sieve[maxn + 10], mem[maxn + 10];
//线性筛
void init()
{
    prime[1] = phi[1] = 1;
    int cnt = 0;
    for (int i = 2; i <= maxn; ++i){
        if (!prime[i]) phi[i] = i - 1, sieve[++cnt] = i;
        for (int j = 1; j <= cnt && i * sieve[j] <= maxn; ++j){
            prime[i * sieve[j]] = 1;
            if (i % sieve[j] == 0){
                phi[i * sieve[j]] = phi[i] * sieve[j];
                break;
            }else{
                phi[i * sieve[j]] = phi[i] * (sieve[j] - 1);
            }
        }
    }
    for (int i = 2; i <= maxn; ++i){
        phi[i] = i * phi[i] + phi[i - 1];
        phi[i] %= mod;
    }
}
//杜教筛,筛i * phi(i)前缀和
ll S(ll n)
{
    if (n <= maxn) return phi[n];
    if (mii[n]) return mii[n];
    ll res = sum2(n);
    for(int l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res -= sum1(l, r) * S(n / l) % mod;
        res %= mod;
        if (res < 0) res += mod;
    }
    return mii[n] = res;
}

int main()
{
    init();
    inv2 = quickpow(2, mod - 2);
    inv6 = quickpow(6, mod - 2);
    int t;
    scanf("%d", &t);
    while (t--){
        ll n, a, b;
        scanf("%lld %lld %lld", &n, &a, &b);
        ll ans = S(n);
        --ans;
        printf("%lld\n", ans * inv2 % mod);
    }
    return 0;
}

莫比乌斯反演:先鸽一下以后遇到这种题再写
[ g c d ( i , j ) = 1 ] ⇔ ∑ d ∣ g c d ( i , j ) μ ( d ) [gcd(i, j) = 1] \Leftrightarrow \sum_{d | gcd(i, j)} \mu(d) [gcd(i,j)=1]dgcd(i,j)μ(d)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值