zoukankan      html  css  js  c++  java
  • 杜教筛 (包括线筛) 莫比乌斯函数前缀和 欧拉函数前缀和 因数和函数前缀和 因子个数前缀和 ( 分析 )

     线筛各种函数   元函数 恒等函数 单位函数 莫比乌斯函数 欧拉函数  因子个数函数 因子和函数    

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1e6+10;
    int e[maxn];
    int I[maxn];
    int ID[maxn];
    int phi[maxn];
    int mu[maxn];
    void init_e() { e[1]=1; }
    void init_I() { int n=maxn-1; for(int i=1;i<=n;i++) I[i]=1;}
    void init_ID(){ int n=maxn-1; for(int i=1;i<=n;i++) ID[i]=i;}
    bool vis[maxn];
    int prime[maxn/7];
    int tot=0;
    void init_mu(){
        int n=maxn-1; tot=0; mu[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) { prime[++tot]=i;  mu[i]=-1; }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0){break;}
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
    void init_phi(){
        int n=maxn-1; tot=0;  phi[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) { prime[++tot]=i; phi[i]=i-1;  }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0){
                    phi[i*prime[j]]=phi[i]*prime[j];
                    break;
                }phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
    int d[maxn];
    ll  dd[maxn];
    int mm[maxn];  // 最小因子相关的信息
    void init_d(){
        int n=maxn-1; tot=0; d[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) {prime[++tot]=i; d[i]=2; mm[i]=2;  }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0){
                    d[i*prime[j]]=d[i]/mm[i]*(mm[i]+1);
                    mm[i*prime[j]]=mm[i]+1;
                    break;
                }
                d[i*prime[j]]=d[i]*2;
                mm[i*prime[j]]=2;
            }
        }
    }
    // ((x+1)*x+1)*x+1; // 转换成多项式 类似hash
    void init_dd(){
        int n=maxn-1; tot=0; dd[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) { prime[++tot]=i; dd[i]=i+1; mm[i]=i+1;  }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0){
                    mm[i*prime[j]]=mm[i]*prime[j]+1;
                    dd[i*prime[j]]=dd[i]/mm[i]*mm[i*prime[j]]  ;
                    break;
                }
                dd[i*prime[j]]=dd[i]*dd[prime[j]];
                mm[i*prime[j]]=1+prime[j];
            }
        }
    }
    int main(){
        init_e();init_I();init_ID();
        init_mu();init_phi();init_d();init_dd();
    }
    View Code

     对于莫比乌斯函数 和 欧拉函数  小于 1e8差不多都可线筛    1e12以内  杜教筛  

    代码针对洛古  p4213  n<=(1<<31)-1  杜教筛

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=5e6+10;
    bool vis[maxn];
    int prime[maxn/7];
    int phi[maxn];
    int mu[maxn];
    int tot=0;
    ll sum_phi[maxn];
    int  sum_mu[maxn];
    void get_mu_phi(){
        int n=maxn-1;
        mu[1]=1;
        phi[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) { prime[++tot]=i; phi[i]=i-1; mu[i]=-1; }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
    
                if(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=1;i<=n;i++) sum_mu[i]=sum_mu[i-1]+mu[i];
        for(int i=1;i<=n;i++) sum_phi[i]=sum_phi[i-1]+phi[i];
    }
    unordered_map<int,int> mp_mu;
    int get_mu(int n){
       if(n<maxn) { return sum_mu[n]; }
       ll ans=0;
       for(int l=2,r;l<=n;l=r+1){
          r=n/(n/l); int d=(n/l);
          if(d<maxn) {  ans+=(r-l+1)*sum_mu[d]; }
          else           {  if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d); ans+=(r-l+1)*mp_mu[d]; }
          if(r==2147483647) break;
       }
       return mp_mu[n]=1-ans;
    }
    unordered_map<int,ll> mp_phi;
    ll get_phi(int n){
       if(n<maxn) { return sum_phi[n]; }
       ll ans=0;
       for(int l=2,r;l<=n;l=r+1){
          r=n/(n/l); int d=(n/l);
          if(d<maxn) {  ans+=(r-l+1)*sum_phi[d]; }
          else           {  if(mp_phi.find(d)==mp_phi.end()) mp_phi[d]=get_phi(d); ans+=(r-l+1)*mp_phi[d]; }
          if(r==2147483647) break;
       }
       return mp_phi[n]=1ll*n*(n+1)/2-ans;
    }
    void work(int n){
        ll x=get_phi(n);
        int y=get_mu(n);
        printf("%lld %d
    ",x,y);
    }
    int main(){
        get_mu_phi(); int T; scanf("%d",&T); while(T--){  int n; scanf("%d",&n); work(n); }
    }
    View Code

    因子和函数前缀和    线筛 (求多个的时候效果突出),杜教都不咋地  整除分块才是王道

    LightOJ - 1098  整除分块代码

    #include<bits/stdc++.h>
    #define ll  long long
    using namespace std;
    int main(){
        int T; scanf("%d",&T); int tot=0;
        while(T--){
            ll n; scanf("%lld",&n);
            ll ans=0;
            for(ll l=1,r;l<=n;l=r+1){
                r=n/(n/l);
                ans+=1ll*(l+r)*(r-l+1)/2*(n/l);
            }
            //cout<<ans<<endl;
            //cout<<1ll*n*(n+1)/2<<endl;
            ans++;
            ans-=n;
            ans-=1ll*n*(n+1)/2;
            if(n==0) ans=0;
            printf("Case %d: %lld
    ",++tot,ans);
        }
    }
    View Code

     杜教推出来而是那个分块的........  通过  I (恒等函数)   id(  单位函数  )  = σ (因子和函数) 

    写个线筛的吧(自己写的  没过过题 随机暴力测了一些样例 过了)

    #include<bits/stdc++.h>
    #define ll  long long
    using namespace std;
    const int maxn=5e6+10;
    int vis[maxn];
    int num[maxn];
    int prime[maxn/7];
    int sigma[maxn]; // yin zi he han shu
    int tot=0;
    int pow(int x,int n){
        int ans=1;
        while(n){
            if(n&1) ans=ans*x;
            x=x*x;
            n=n/2;
        }
        return ans;
    }
    void inint(){
        int n=maxn-1;
        vis[1]=1;
        sigma[1]=1;
        for(int i=2;i<=n;i++){
              //  cout<<i<<endl;
            if(vis[i]==0) {
                prime[++tot]=i; vis[i]=i; num[i]=1; sigma[i]=i+1;
            }
            for(int j=1;j<=tot&&i*prime[j]<=n;j++){
                vis[i*prime[j]]=prime[j];
                if(i%prime[j]==0){
                    num[i*prime[j]]=num[i]+1;;
                    sigma[i*prime[j]]=sigma[i]*(1-pow(vis[i],num[i]+1+1)) / (1-pow(vis[i],num[i]+1));
                    break;
                }else {
                    num[i*prime[j]]=1;
                    sigma[i*prime[j]]=sigma[i]*(1+prime[j]);
                }
            }
        }
    }
    int main(){  //cout<<pow(2,5)<<endl;
        inint();  //cout<<sigma[4]<<endl;
        int tot=0;
    while(1){
        int n; cin>>n;
        cout<<sigma[n]<<endl;
        int ans=0;
        for(int i=1;i<=n;i++){
            if(n%i==0) ans+=i;
        }
        cout<<ans<<endl;
    }
    }
    View Code

    hdu 5608  莫比乌斯反演+杜教筛

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=5e6+10;
    const int mod=1e9+7;
    const int inv2=500000004;
    const int inv4=250000002;
    const int inv6=166666668;
    bool vis[maxn];
    int prime[maxn/7];
    int mu[maxn];
    int tot=0;
    int  sum_mu[maxn];
    void get_mu_phi(){
        int n=maxn-1;
        mu[1]=1;
        for(int i=2;i<=n;i++){
            if(vis[i]==0) { prime[++tot]=i;  mu[i]=-1; }
            for(int j=1;j<=tot && i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(i%prime[j]==0){
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
        for(int i=1;i<=n;i++) sum_mu[i]=sum_mu[i-1]+mu[i];
    }
    unordered_map<ll,ll> mp_mu;
    ll get_mu(ll n){
       if(n<maxn) { return sum_mu[n]; }
       ll ans=0;
       for(int l=2,r;l<=n;l=r+1){
          r=n/(n/l);        int d=(n/l);
          if(d<maxn)     {  ans+=1ll*(r-l+1)*sum_mu[d]%mod; }
          else           {  if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d); ans+=1ll*(r-l+1)*mp_mu[d]%mod; }
       }
       return mp_mu[n]=(1-ans)%mod;
    }
    int add(int x){
        int ans=1ll*x*(x+1)%mod*(2*x+1)%mod*inv6%mod;
        ans-=1ll*3*(x+1)%mod*x%mod*inv2%mod; ans=ans%mod;
        ans+=1ll*2*x%mod; ans=ans%mod;
        return ans;
    }
    int make(int l,int r){  return ( add(r)-add(l-1) )%mod; }
    void work(int n){
        ll ans=0;
        for(int l=1,r;l<=n;l=r+1){
            r=n/(n/l);  int d=n/l;
            if(d<maxn){
                ans+=1ll*make(l,r)*sum_mu[d]%mod;
            }else {
                if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d);
                ans+=1ll*make(l,r)*mp_mu[d]%mod;
            }
        }
        printf("%lld
    ",(ans%mod+mod)%mod);
    }
    int main(){
        get_mu_phi();
        int T; scanf("%d",&T);
        while(T--){
            int n; scanf("%d",&n); work(n);
        }
    }
    View Code

     https://blog.csdn.net/v5zsq/article/details/52116285   大神的写法 (学不来)  

     https://www.cnblogs.com/acjiumeng/p/9739793.html  学不来的写法

      

  • 相关阅读:
    vue语法
    第3章 语言基础(上)
    第2章 HTML中的JavaScript
    第1章 什么是JavaScript
    附录 A ES6附加特性
    第14章 跨浏览器开发技巧
    第13章 历久弥新的事件
    第12章 DOM操作
    第11章 代码模块化
    第10章 正则表达式
  • 原文地址:https://www.cnblogs.com/Andromeda-Galaxy/p/11161894.html
Copyright © 2011-2022 走看看