zoukankan      html  css  js  c++  java
  • 斯特林数及斯特林反演

    此文章涉及到斯特林数性质及斯特林反演,例题总结与应用篇(Longrightarrow)点这里

    ({largecolor{SpringGreen}{历史小芝士}})

    在组合数学中,斯特林((Stirling))数可指两类数,第一类斯特林数和第二类斯特林数
    这些均由(18)世纪数学家(James Stirling)提出的,并在著作《(Methodous Differentialis)》中首次使用

    自此,斯特林数成为又一广泛运用到处理组合问题的一大利器

    ({largecolor{SpringGreen}{第一类斯特林数}})

    定义

    (egin{bmatrix}n\m end{bmatrix})表示(n)个元素分成(m)个环的方案数

    显然:$$egin{bmatrix}nm end{bmatrix}=egin{bmatrix}n-1m-1 end{bmatrix}+(n-1)*egin{bmatrix}n-1m end{bmatrix}$$

    理解:考虑从(n-1)个元素推过来,如果两个空环肯定是不符合的
    (~~~~~~~~~~)空一个环则单独成环,如果(n-1)的时候就没有空环就任意放在一个元素前

    性质

    • (n!=sumlimits_{i=0}^n egin{bmatrix}n\i end{bmatrix})

    理解:其实本质就是置换,一个环则为一组轮换,每种排列都会对应着唯一 一种置换

    • (x^{underline n}=sumlimits_{i=0}^n egin{bmatrix}n\i end{bmatrix}(-1)^{n-i}x^i\)

    归纳法:

    [egin{aligned}\ x^{underline {n+1}}&=(x-n)x^{underline n}\ &=(x-n)sumlimits_{i=0}^n egin{bmatrix}n\i end{bmatrix}(-1)^{n-i}x^i\ &=xsumlimits_{i=0}^{n} egin{bmatrix}n\i end{bmatrix}(-1)^{n-i}x^{i}-nsumlimits_{i=0}^n egin{bmatrix}n\i end{bmatrix}(-1)^{n-i} x^i\ &=sumlimits_{i=0}^{n} egin{bmatrix}n\i end{bmatrix}(-1)^{n-i}x^{i+1}-nsumlimits_{i=0}^{n+1} egin{bmatrix}n\i end{bmatrix}(-1)^{n-i} x^i\ &=sumlimits_{i=1}^{n+1} egin{bmatrix}n\i-1 end{bmatrix}(-1)^{n-i+1}x^{i}+nsumlimits_{i=0}^{n+1} egin{bmatrix}n\i end{bmatrix}(-1)^{n-i+1} x^i\ &=sumlimits_{i=1}^{n+1} ( egin{bmatrix}n\i-1 end{bmatrix} +n*egin{bmatrix}n\i end{bmatrix})(-1)^{n-i+1}x^{i}\ &=sumlimits_{i=1}^{n+1} egin{bmatrix}n+1\i end{bmatrix}(-1)^{n-i+1}x^{i}\ &=sumlimits_{i=0}^{(n+1)} egin{bmatrix}n+1\i end{bmatrix}(-1)^{(n+1)-i}x^{i}\ end{aligned}]

    • (x^{overline n}=sum_{i=0}^n egin{bmatrix}n\i end{bmatrix}x^i)

    证明类上,不再赘述

    求第一类斯特林数

    • [sum_{i=0}^n egin{bmatrix}n\i end{bmatrix}x^i=prod_{i=0}^{n-1}(x+i) ]

    (egin{array}{c c c}~&0&1&2&3&4\0&0&0&0&0&0\1&0&1&0&0&0\2&0&1&1&0&0\3&0&2&3&1&0\4&0&6&11&6&1end{array})

    其实把表刷出来就差不多了,可以理解为根据(egin{bmatrix}n\m end{bmatrix}=egin{bmatrix}n-1\m-1 end{bmatrix}+(n-1)*egin{bmatrix}n-1\m end{bmatrix})逐渐转移

    至此,我们可以通过分治(FFTO(nlog^2n))求出一行的第一类斯特林数

    • 还有一种类似于多项式求逆模式(O(nlogn))的方法

    [F(x)^n=prodlimits_{i=0}^{n-1}(x+i),F(x)^{2n}=F(x)^nF(x+n)^n ]

    考虑当我们求出(F(x)^n=sumlimits_{i=0}^{n}a_ix^i)

    [egin{aligned}\ F(x+n)^{n}&=sumlimits_{i=0}^{n}a_i(x+n)^i\ &=sumlimits_{i=0}^na_isumlimits_{j=0}^i{ichoose j}n^{i-j}x^j\ &=sumlimits_{i=0}^n(sumlimits_{j=i}^n {jchoose i}n^{j-i}a_j)x^i\ &=sumlimits_{i=0}^n(sumlimits_{j=i}^n frac{j!}{i!(j-i)!}n^{j-i}a_j)x^i\ &=sumlimits_{i=0}^n (i!)^{-1}x^i (sumlimits_{j=i}^n (frac{n^{j-i}}{(j-i)!})cdot (j!a_j))\ end{aligned}]

    我们通过左半部分系数能得到右半部分系数,再相乘一下就得到了总体的系数

    Code

    留有少量注释

    #include<bits/stdc++.h>
    typedef long long LL;
    const LL mod=998244353,g=3,maxn=1e6+9;
    inline LL Pow(LL base,LL b){
        LL ret(1);
        while(b){
            if(b&1) ret=ret*base%mod; base=base*base%mod; b>>=1;
        }return ret;
    }
    LL r[maxn];
    inline LL Fir(LL n){
        LL limit(1),len(0);
        while(limit<(n<<1)){
            limit<<=1; ++len;
        }
        for(LL i=0;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<len-1);
        return limit;
    }
    inline void NTT(LL *a,LL n,LL type){
        for(LL i=0;i<n;++i) if(i<r[i]) std::swap(a[i],a[r[i]]);
        for(LL mid=1;mid<n;mid<<=1){
            LL wn(Pow(g,(mod-1)/(mid<<1))); if(type==-1) wn=Pow(wn,mod-2);
            for(LL R=mid<<1,j=0;j<n;j+=R)
                for(LL k=0,w=1;k<mid;++k,w=w*wn%mod){
                	LL x(a[j+k]),y(w*a[j+mid+k]%mod);
                	a[j+k]=(x+y)%mod; a[j+mid+k]=(x-y+mod)%mod;
                }
        }
        if(type==-1){
            LL ty(Pow(n,mod-2)); for(LL i=0;i<n;++i) a[i]=a[i]*ty%mod;
        }
    }
    LL T[maxn],F[maxn],H[maxn],G[maxn],fac[maxn],fav[maxn],tmp[maxn],sum[maxn],B[maxn];
    inline void Mul(LL n,LL *a,LL *b,LL *ans){
        LL limit(Fir(n));
        NTT(a,limit,1); NTT(b,limit,1);
        for(LL i=0;i<limit;++i) ans[i]=a[i]*b[i]%mod;
        NTT(ans,limit,-1);
    }
    inline void Solve(LL n,LL *a){
        if(!n){ a[0]=1; return; }
        if(n==1){ a[1]=1; return; }
        LL len(n/2);
        Solve(len,a);
        
        LL limit(Fir(len+1));
        for(LL i=0;i<=len;++i) F[i]=Pow(len,i)*fav[i]%mod;
        for(LL i=0;i<=len;++i) H[i]=fac[i]*a[i]%mod;
        for(LL i=0;i<=(len>>1);++i) std::swap(H[i],H[len-i]);
        for(LL i=len+1;i<limit;++i) F[i]=H[i]=0;
        NTT(F,limit,1); NTT(H,limit,1);
        for(LL i=0;i<limit;++i) G[i]=F[i]*H[i]%mod;
        NTT(G,limit,-1);
        for(LL i=0;i<=len;++i) tmp[i]=G[len-i]*Pow(fac[i],mod-2)%mod;//right
        
        Mul(len+1,a,tmp,B);//left * right
        for(LL i=0;i<=(len<<1);++i) a[i]=B[i];
        for(LL i=(len<<1)+1;i<=(len<<2);++i) a[i]=tmp[i]=0;
        
        if(n&1){
            for(LL i=0;i<n;++i) T[i]=a[i];
            for(LL i=1;i<=n;++i) a[i]=(T[i-1]+(n-1)*T[i]%mod)%mod;
        }
    }
    inline LL Get_c(LL n,LL m){
        return fac[n]*fav[m]%mod*fav[n-m]%mod;
    }
    LL n;
    LL ans[maxn];
    int main(){
        scanf("%lld",&n);
        fac[0]=fac[1]=1;
        for(LL i=2;i<=n;++i) fac[i]=fac[i-1]*i%mod;
        fav[n]=Pow(fac[n],mod-2);
        for(LL i=n;i>=1;--i) fav[i-1]=fav[i]*i%mod;
        Solve(n,ans);
    	for(LL i=0;i<=n;++i) printf("%lld ",ans[i]);printf("
    ");
    	return 0;
    }
    

    ({largecolor{SpringGreen}{第二类斯特林数}})

    定义

    (egin{Bmatrix}n\mend{Bmatrix})表示(n)个有区别的小球丢进(m)个无区别的盒子,无空盒子的方案数

    显然:$$egin{Bmatrix}nmend{Bmatrix}=egin{Bmatrix}n-1m-1end{Bmatrix}+m*egin{Bmatrix}n-1mend{Bmatrix}$$

    理解:考虑从(n-1)个小球推过来,如果两个空盒子肯定是不符合的
    (~~~~~~~~~~)空一个盒子则只能放到那个空盒子里面了,如果(n-1)的时候就没有空箱子就随便放

    性质

    [m^n=sum_{i=0}^{m}egin{Bmatrix}n\iend{Bmatrix}*i!*C(m,i) ]

    当然也可以写成:$$m^n=sumlimits_{i=0}^m egin{Bmatrix}niend{Bmatrix}*m^{underline i}$$

    到后面反演时我们会这样写:$$m^n=sumlimits_{i=0}^n egin{Bmatrix}niend{Bmatrix}*m^{underline i}$$
    看看后面的(m^{underline i})就懂了

    理解:(m^n)(n)个有区别的小球丢进(m)个有区别的盒子,允许空盒子
    (~~~~~~~~~~)枚举有效盒子的个数,再从(m)个盒子选(i)个盒子,然后(n)个小球丢进(i)个盒子

    转换到组合表示

    第二类斯特林数显然是和排列组合有关系的,转换过来:$$egin{Bmatrix}nmend{Bmatrix}=frac{1}{m!}sumlimits_{k=0}^m(-1)^kC(m,k)(m-k)^n$$

    理解:如果空箱子的情况我们也算进去,答案显然是(frac{m^n}{m!})
    (~~~~~~~~~~)反过来求第二类斯特林数,又得减掉这种情况:
    (~~~~~~~~~~)(k)个空盒子,然后小球放到其他的盒子里
    (~~~~~~~~~~)但最后我们求出来的答案为有区别的盒子,转换过来要(×frac{1}{m!})

    求第二类斯特林数

    大概都能猜到是卷积形式了吧,随手展开一下:

    [egin{aligned}\ egin{Bmatrix}n\mend{Bmatrix}&=frac{1}{m!}sumlimits_{k=0}^m(-1)^kfrac{m!}{k!(m-k)!}(m-k)^n\ &=sumlimits_{k=0}^mfrac{(-1)^k(m-k)^n}{k!(m-k)!}\ end{aligned}]

    至此,我们能实现(O(nlogn))求出(S(n))这一行的第二类斯特林

    第二类斯特林数与自然数幂的关系

    [egin{aligned}\ Sum(n)&=sumlimits_{i=0}^n i^k\ &=sumlimits_{i=0}^nsumlimits_{j=0}^kegin{Bmatrix}k\j end{Bmatrix}i^{underline j}\ &=sumlimits_{j=0}^kegin{Bmatrix}k\j end{Bmatrix}sumlimits_{i=0}^n i^{underline j}\ &=sumlimits_{j=0}^k egin{Bmatrix}k\j end{Bmatrix}j!sumlimits_{i=0}^nC_i^j\ &=sumlimits_{j=0}^k egin{Bmatrix}k\j end{Bmatrix}j!C_{n+1}^{j+1}\ &=sumlimits_{j=0}^k egin{Bmatrix}k\j end{Bmatrix} frac{(n+1)^{underline {j+1}}}{j+1}\ end{aligned}]

    关于(sumlimits_{i=0}^nC_i^j=C_{n+1}^{j+1})的理解:枚举(j+1)的右端点(i+1),则相当于从(i)个点中选(j)个点

    ({largecolor{SpringGreen}{斯特林反演}})

    定义

    斯特林反演:(f(n)=sumlimits_{k=0}^n egin{Bmatrix}n\k end{Bmatrix}g(k)Longleftrightarrow g(n)=sumlimits_{k=0}^n(-1)^{n-k}egin {bmatrix} n\k end{bmatrix}f(k))

    总结上面我们所推倒的性质

    • (x^{underline n}=sumlimits_{i=0}^n egin{bmatrix}n\i end{bmatrix}(-1)^{n-i}x^i,x^{overline n}=sum_{i=0}^n egin{bmatrix}n\i end{bmatrix}x^i)
    • (m^n=sumlimits_{i=0}^n egin{Bmatrix}n\iend{Bmatrix}*m^{underline i})

    补充

    [x^{underline n}=(-1)^n (-x)^{overline n},x^{overline n}=(-1)^n (-x)^{underline n} ]

    前置

    我们先证这个反转公式

    [egin{aligned}displaystyle sum_{k=m}^n (-1)^{n-k}egin{bmatrix}n\kend{bmatrix} egin{Bmatrix}k\mend{Bmatrix}=[m=n]\ sum_{k=m}^n (-1)^{n-k}egin{Bmatrix}n\kend{Bmatrix} egin{bmatrix}k\mend{bmatrix}=[m=n]end{aligned}]

    反转公式1

    [egin{aligned}\ m^{underline n}&=sumlimits_{i=0}^n egin{bmatrix}n\iend{bmatrix}(-1)^{n-i}m^i\ &=sumlimits_{i=0}^n egin{bmatrix}n\iend{bmatrix}(-1)^{n-i}sumlimits_{j=0}^i egin{Bmatrix}i\jend{Bmatrix}m^{underline j}\ &=sumlimits_{i=0}^n m^{underline i}sumlimits_{j=i}^n (-1)^{n-j} egin{bmatrix}n\jend{bmatrix} egin{Bmatrix}j\iend{Bmatrix}\ end{aligned}]

    反转公式2

    [egin{aligned}\ m^n&=sumlimits_{i=0}^negin{Bmatrix}n\iend{Bmatrix}m^{underline i}\ &=sumlimits_{i=0}^negin{Bmatrix}n\iend{Bmatrix}(-1)^i(-m)^{overline i}\ &=sumlimits_{i=0}^negin{Bmatrix}n\iend{Bmatrix}(-1)^isumlimits_{j=0}^i egin{bmatrix}i\jend{bmatrix}(-m)^j\ &=sumlimits_{i=0}^n m^isumlimits_{j=i}^n(-1)^{i-j} egin{Bmatrix}n\jend{Bmatrix}egin{bmatrix}j\iend{bmatrix}\ end{aligned}]

    推式

    已知:(g(n)=sumlimits_{k=0}^n(-1)^{n-k}egin {bmatrix} n\k end{bmatrix}f(k))

    [egin{aligned}\ f(n)&=sumlimits_{k=0}^n [k=n]f(k)\ &=sumlimits_{k=0}^nsumlimits_{j=k}^n egin {Bmatrix} n\j end{Bmatrix}egin {bmatrix} j\k end{bmatrix}(-1)^{j-k}f(k)\ &=sumlimits_{k=0}^n egin {Bmatrix} n\k end{Bmatrix}sumlimits_{j=0}^k (-1)^{k-j}egin {bmatrix} k\j end{bmatrix}f(j)\ &=sumlimits_{k=0}^n egin {Bmatrix} n\k end{Bmatrix}g(k)\ end{aligned}]

    ({largecolor{SpringGreen}{斯特林数应用}})

    总结

  • 相关阅读:
    Lambda表达式、依赖倒置
    ASP.NET vNext 概述
    Uname
    RHEL4 i386下安装rdesktop【原创】
    Taxonomy of class loader problems encountered when using Jakarta Commons Logging(转)
    How to decompile class file in Java and Eclipse
    先有的资源,能看的速度看,不能看的,抽时间看。说不定那天就真的打不开了(转)
    Google App Engine 学习和实践
    【VBA研究】VBA通过HTTP协议实现邮件轨迹跟踪查询
    js正則表達式语法
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10700231.html
Copyright © 2011-2022 走看看