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

    前置姿势

    Mobius反演

    杜教筛

    下面考虑一个问题,你手里有一个积性函数(f(n)),定义(S_f(n)=sumlimits_{i=1}^n f(i))(即(f)的前缀和)。

    对与一个(n),你现在要快速求出(S_f(n)),假设线性筛都死了

    我们先随便找一个积性函数(g),然后跟(f)卷上,得到第三个积性函数(h=f*g),那么

    [h(n)=sumlimits_{dmid n} f(d)g(frac{n}{d}) ]

    考虑求(S_h(n)),推柿子

    [egin{aligned}S_h(n)&=sumlimits_{i=1}^n sumlimits_{dmid i} f(frac{i}{d})g(d) \&=sumlimits_{d} g(d) sumlimits_{i=1}^{lfloor n/d floor} f(i) \&=sumlimits_{d=1}^n g(d)S_f(lfloor frac{n}{d} floor)end{aligned} ]

    因为(g)是积性函数,必然有(g(1)=1),所以

    [S_f(n)=g(1)S_f(n)=S_h(n)-sumlimits_{i=2}^n g(i)S_f(lfloor frac{n}{i} floor) ]

    如果说(h)(g)的前缀和能快速求出来的话,后面那一部分我们只要数论分块就好了,这样就能做到在非线性时间内求出(f)的前缀和。

    具体的复杂度并不会算qwq......好像说裸的杜教筛是(O(n^{3/4}))的,但如果筛出前(n^{2/3})个前缀和后就变成(O(n^{2/3}))了,总之尽可能多的线性筛出能处理的答案,这样复杂度并不会差,杜教筛的时候记忆化就好了。

    扯了那么多,来看板子题吧:[模板]杜教筛

    让你求(varphi)(mu)的前缀和,(n le 2^{31}-1),所以说线性筛死了......

    考虑杜教筛,我们先来看莫比乌斯函数好了

    考虑到(sumlimits_{dmid n} mu(d) = varepsilon(n)),即(mu*I=varepsilon),取(g=I),与(mu)卷积后得到单位元函数,我们知道对于(nge 1)(S_{varepsilon}(n)equiv 1),这个就非常nice,然后(I)的前缀和就是(n),套柿子

    [S_{mu}(n)=S_{varepsilon}(n)-sumlimits_{i=2}^n I(i)S_{mu}(lfloorfrac{n}{i} floor)=1-sumlimits_{i=2}^n S_{mu}(lfloor frac{n}{i} floor) ]

    记忆化然后数论分块即可。

    然后是(varphi),有式子(sumlimits_{dmid n} varphi(d)=n),这里给出一个简(gan)单(xing)的证(li)明(jie)

    显然(n=sumlimits_{dmid n} sumlimits_{i=1}^n [gcd(n,i)=d]),后面的柿子也就是(sumlimits_{i=1}^{n/d} [gcd(n,i)=1]=varphi(frac{n}{d})),所以(n=sumlimits_{dmid n} varphi(frac{n}{d})=sumlimits_{dmid n} varphi(d))

    于是(varphi*I=id)怎么有是I,于是取(g=I),得到(h=varphi*I=id),套柿子

    [S_{varphi}(n)=S_{id}(n)-sumlimits_{i=2}^n I(i)S_{varphi}(lfloorfrac{n}{i} floor)=frac{1}{2}n(n+1)-sumlimits_{i=2}^n S_{varphi}(lfloorfrac{n}{i} floor) ]

    同样记忆化+数论分块就好了。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for (int i=(a);i<(b);++i)
    #define per(i,a,b) for (int i=(a)-1;i>=(b);--i)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    #define SZ(x) ((int)(x).size())
    typedef double db;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    
    const int maxn=2e6,N=maxn+10;
    int p[N],pn;
    ll mu[N],phi[N],smu[N],sphi[N];
    bitset<N> vis;
    
    inline ll s1(ll l,ll r) {return 1ll*(r-l+1)*(l+r)/2;}
    
    void init(int n) {
        mu[1]=1,phi[1]=1;
        rep(i,2,n+1) {
            if(!vis[i]) {
                mu[i]=-1,phi[i]=i-1;
                p[pn++]=i;
            }
            for(int j=0;j<pn&&i*p[j]<=n;j++) {
                vis[i*p[j]]=1;
                if(i%p[j]==0) {
                    mu[i*p[j]]=0;
                    phi[i*p[j]]=phi[i]*p[j];
                    break;
                }
                else mu[i*p[j]]=-mu[i],phi[i*p[j]]=phi[i]*phi[p[j]];
            }
        }
        rep(i,1,n+1) smu[i]=smu[i-1]+mu[i],sphi[i]=sphi[i-1]+phi[i];
    }
    
    map<int,ll> phisum,musum;
    ll Sphi(int n) {
        if(n<=maxn) return sphi[n];
        if(phisum.count(n)) return phisum[n];
        ll ans=s1(1,n);
        for(ll l=2,r=0;l<=n;l=r+1) {
            r=n/(n/l);
            ans-=Sphi(n/l)*(r-l+1);
        }
        return phisum[n]=ans;
    }
    ll Smu(int n) {
        if(n<=maxn) return smu[n];
        if(musum.count(n)) return musum[n];
        ll ans=1;
        for(ll l=2,r=0;l<=n;l=r+1) {
            r=n/(n/l);
            ans-=Smu(n/l)*(r-l+1);
        }
        return musum[n]=ans;
    }
    
    int main() {
        init(maxn);
        int _,n; for(scanf("%d",&_);_;_--) {
            scanf("%d",&n);
            printf("%lld %lld
    ",Sphi(n),Smu(n));
        }
        return 0;
    }
    
  • 相关阅读:
    删库跑路技术白皮书
    linux shell文件截取前几行,后几行,中间几行命令
    python 带参数 单步执行 (调试 pdb)
    分区助手专业版 v6.2 如何把win10系统迁移到SSD固态硬盘
    GUPPY 3.1.5 安装
    Java调用其他语言
    python代码中获取python版本号的方法
    f-Strings:Python 3格式字符串的新方法(f字符串)
    Centos 安装 pigz
    #!/usr/bin/env python与#!/usr/bin/python的区别
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12367629.html
Copyright © 2011-2022 走看看