zoukankan      html  css  js  c++  java
  • 杜教筛

    其中利用了迪利克雷卷积的性质,做到快速求和

    常见的迪利克雷卷积

    [varphi * I = id ]

    [mu * I = e([n = 1]) ]

    [mu * i * varphi = e * varphi ]

    [mu * id = varphi ]

    杜教筛

    比如我们需要求

    [S(n) = sum_{i = 1} ^ n f(i) ]

    找一个积性函数 (g)

    考虑

    [sumlimits_{i = 1} ^ n (f * g)(i) ]

    [=sum_{i = 1} ^ n sum_{d | i} f(d) g(frac i d) ]

    [= sum_{d = 1} ^ n g(d) sum_{i le frac n d} f(i) ]

    [= sum_{d = 1} ^ n g(d) S(frac n d) ]

    考虑把第一项拿出来

    [g(1) s(n) = sum_{d = 1} ^ n g(d) S(frac n d) - sum_{d = 2} ^ ng(d) S(frac n d) ]

    [g(1) s(n) = sumlimits_{i = 1} ^ n (f * g)(i) - sum_{d = 2} ^ ng(d) S(frac n d) ]

    如果可以快速求得 (sumlimits_{i = 1} ^ n (f * g)(i)) 那就可以整除分块递归求 (sumlimits_{d = 2} ^ n g(d) S(frac n d))

    • (sum varphi(i))

    [f = varphi, g = I, f * g = id ]

    [g(1) = 1 ]

    [sum_g(n) = n ]

    [sum_{i = 1} ^ n (f * g) (i) = sum_{i = 1} ^ n id(i) = frac {(1 + n) * n} 2 ]

    • (sum mu(i))

    [f = mu, g = I, f * g = e ]

    [g(1) = 1 ]

    [sum_g(n) = n ]

    [sum_{i = 1} ^ n (f * g)(i) = 1 ]

    (code)

    #include <bits/stdc++.h>
    #include <tr1/unordered_map>
    using namespace std :: tr1;
    using namespace std;
    #define rg register
    #define gc getchar
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    inline int read(){
        rg char ch = gc();
        rg int x = 0, f = 0;
        while(!isdigit(ch)) f |= (ch == '-'), ch = gc();
        while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
        return f ? -x : x;
    }
    const int N = 2e6 + 5;
    int prime[N], pre[N], cnt;
    #define ll unsigned long long
    ll mu[N], phi[N];
    unordered_map<int, ll> ansm, ansp;
    const int mod = 1000013;
    // struct Hash_map{
    //     int head[mod], nxt[N], id[N], tot;
    //     ll val[N * 4];
    //     inline ll find(int x){
    //         for(int i = head[x % mod]; i; i = nxt[i])
    //             if(id[i] == x) return val[i];
    //         return 2e18;
    //     }
    //     inline void add(int x, ll y){
    //         for(int i = head[x % mod]; i; i = nxt[i])
    //             if(id[i] == x) return;
    //         val[++tot] = y;
    //         id[tot] = x;
    //         nxt[tot] = head[x % mod];
    //         head[x % mod] = tot;
    //     }
    // }ansp, ansm;
    inline void ola(){
        mu[1] = 1;
        phi[1] = 1;
        for(int i = 2; i < N; ++i){
            if(!pre[i]){
                pre[i] = i;
                prime[++cnt] = i;
                mu[i] = -1;
                phi[i] = i - 1;
            }
            for(int j = 1; j <= cnt && prime[j] * i < N; ++j){
                pre[prime[j] * i] = prime[j];
                if(prime[j] == pre[i]){
                    mu[prime[j] * i] = 0;
                    phi[prime[j] * i] = phi[i] * prime[j];
                    break;
                }
                mu[prime[j] * i] = mu[i] * -1;
                phi[prime[j] * i] = phi[i] * (prime[j] - 1);
            }
        }
        for(int i = 2; i < N; ++i) mu[i] += mu[i - 1], phi[i] += phi[i - 1];
    }
    ll get_sum_phi(int n){
        if(n < N) return phi[n];
        if(ansp[n]) return ansp[n];
        // ll to = ansp.find(n);
        if(to != 2e18) return to;
        ll res = (ll) (1 + n) * n >> 1;
        for(ll l = 2, r; l <= n; l = r + 1){
            r = n / (n / l);
            res -= (r - l + 1) * get_sum_phi(n / l);
        }
        // ansp.add(n, res);
        return ansp[n] = res;
    }
    ll get_sum_mu(int n){
        if(n < N) return mu[n];
        if(ansm[n]) return ansm[n];
        // ll to = ansm.find(n);
        if(to != 2e18) return to;
        ll res = 1;
        for(ll l = 2, r; l <= n; l = r + 1){
            r = n / (n / l);
            res -= (r - l + 1) * get_sum_mu(n / l);
        }
        // ansm.add(n, res);
        return ansm[n] = res;
    }
    inline void Main(){
        int n = read();
        printf("%lld %lld
    ", get_sum_phi(n), get_sum_mu(n));
    }
    signed main(){
        ola();
        int t = read();
        while(t--) Main();
        gc(), gc();
        return 0;
    }
    
  • 相关阅读:
    php数组通过值获得键
    php 重定向
    php 数组排序
    SVN使用操作
    Java + Jsp web 项目
    create-react-app搭建React项目
    双向链表实现查询、删除、插入、末尾增加
    顺序存储结构实现查询、删除、插入、末尾增加
    单向链表实现查询、删除、插入、末尾增加
    数列
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13054131.html
Copyright © 2011-2022 走看看