zoukankan      html  css  js  c++  java
  • P4213 【模板】杜教筛(杜教筛)题解

    题意:

    (sum_{i=1}^nvarphi(i))(sum_{i=1}^nmu(i))

    思路:

    由性质可知:(mu*I=epsilon,varphi*I=id)那么可得:

    [S_{varphi}(n)=sum_{i=1}^nvarphi(i)=frac{(n+1)n}{2}-sum_{i=2}^nS_{varphi}(lfloorfrac{n}{i} floor)\ S_{mu}(n)sum_{i=1}^nmu(i)=1-sum_{i=2}^nS_{mu}(lfloorfrac{n}{i} floor) ]

    然后用现预处理一部分答案,然后数论分块其他答案,用记忆化记录中间答案。
    很卡常...

    还有一种不用(map)的方法,详见代码(2)

    代码:

    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    #include<unordered_map>
    typedef long long ll;
    typedef unsigned long long ull;
    using namespace std;
    const int maxn = 6000000 + 5;
    const ll MOD = 998244353;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    
    int vis[maxn];
    int prime[maxn], cnt;
    int N = 6000000;
    ll mu[maxn], phi[maxn];
    unordered_map<int, int> mmu;
    unordered_map<int, ll> mphi;
    void init(int n){
        cnt = 0;
        mu[1] = 1;
        phi[1] = 1;
        for(int i = 2; i <= n; i++){
            if(!vis[i]){
                prime[cnt++] = i;
                mu[i] = -1;
                phi[i] = i - 1;
            }
            for(int j = 0; j < cnt && prime[j] * i <= n; j++){
                vis[i * prime[j]] = 1;
                if(i % prime[j] == 0){
                    mu[i * prime[j]] = 0;
                    phi[i * prime[j]] = phi[i] * prime[j];
                    break;
                }
                mu[i * prime[j]] = -mu[i];
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    
        for(int i = 2; i <= n; i++){
            phi[i] += phi[i - 1];
            mu[i] += mu[i - 1];
        }
    }
    
    ll Sphi(int n){
        if(n <= N) return phi[n];
        if(mphi.count(n)) return mphi[n];
        ll ans = 1LL * n * (1 + n) >> 1LL;
        for(int l = 2, r; l <= n; l = r + 1){
            r = min(n / (n / l), n);
            ans -= (r - l + 1) * Sphi(n / l);
        }
        return mphi[n] = ans;
    }
    int Smu(int n){
        if(n <= N) return mu[n];
        if(mmu.count(n)) return mmu[n];
        int ans = 1;
        for(int l = 2, r; l <= n; l = r + 1){
            r = min(n / (n / l), n);
            ans -= (r - l + 1) * Smu(n / l);
        }
        return mmu[n] = ans;
    }
    
    int main(){
        init(N);
        int T;
        scanf("%d", &T);
        while(T--){
            int n;
            scanf("%d", &n);
            printf("%lld %d
    ", Sphi(n), Smu(n));
        }
        return 0;
    }
    
    
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    typedef unsigned long long ull;
    using namespace std;
    const int maxn = 6000000 + 5;
    const ll MOD = 998244353;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    int vis[maxn];
    int prime[maxn], cnt;
    int N = 6000000;
    ll phi[maxn], mphi[100000];
    int mu[maxn], mmu[100000];
    int vis2[100000];
    int n, up;
    void init(int n){
        cnt = 0;
        mu[1] = 1;
        phi[1] = 1;
        for(int i = 2; i <= n; i++){
            if(!vis[i]){
                prime[cnt++] = i;
                mu[i] = -1;
                phi[i] = i - 1;
            }
            for(int j = 0; j < cnt && prime[j] * i <= n; j++){
                vis[i * prime[j]] = 1;
                if(i % prime[j] == 0){
                    mu[i * prime[j]] = 0;
                    phi[i * prime[j]] = phi[i] * prime[j];
                    break;
                }
                mu[i * prime[j]] = -mu[i];
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    
        for(int i = 2; i <= n; i++){
            phi[i] += phi[i - 1];
            mu[i] += mu[i - 1];
        }
    }
    int getmu(int x){
        return x <= N? mu[x] : mmu[up / x];
    }
    ll getphi(int x){
        return x <= N? phi[x] : mphi[up / x];
    }
    void solve(int n){
        int t = up / n;
        if(n <= N) return;
        if(vis2[t]) return;
        vis2[t] = 1;
        mmu[t] = 1, mphi[t] = 1LL * n * (n + 1) / 2;
        for(int l = 2, r; l <= n; l = r + 1){
            r = n / (n / l);
            solve(n / l);
            mmu[t] -= (r - l + 1) * getmu(n / l);
            mphi[t] -= (r - l + 1) * getphi(n / l);
        }
    }
    
    int main(){
        init(N);
        int T;
        scanf("%d", &T);
        while(T--){
            scanf("%d", &n);
            up = n;
            if(n <= N) printf("%lld %d
    ", phi[n], mu[n]);
            else{
                memset(vis2, 0, sizeof(vis2));
                solve(n);
                printf("%lld %d
    ", mphi[1], mmu[1]);
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    vsftpd配置再次冲击Ubuntu之server篇
    update关联其他表批量更新数据
    丁丁的成长7
    Winform中使用PictureBox显示及修改数据库中的照片
    Apache HTTP Server 与 Tomcat 的三种连接方式
    丁丁的成长5
    tomcat的自动启动再次冲击Ubuntu之server篇
    再严重的感冒,马上就好【转】
    基本配置2被忽悠进了CentOS 6
    丁丁的成长6
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11461267.html
Copyright © 2011-2022 走看看