zoukankan      html  css  js  c++  java
  • [笔记] 斯特林数

    第一类斯特林数

    (egin{bmatrix}n\ k end{bmatrix}) 表示(n) 个有区别的元素划分成(k) 个环的方案数。

    (egin{bmatrix}n\ 1 end{bmatrix}=(n-1)!) 此时的每种轮换对应(n) 个循环同构的排列。

    (egin{bmatrix}n\ n end{bmatrix} = 1 ,egin{bmatrix}n\ n-1 end{bmatrix} = {n choose 2}) 因为当每个轮换都是单元素或双元素时,轮换与子集是等价的。

    (egin{bmatrix}n\ k end{bmatrix}=(n-1)egin{bmatrix}n-1\ k end{bmatrix}+egin{bmatrix}n-1\ k-1 end{bmatrix},ngeq1)

    (n! = sumlimits_{k=0}^n egin{bmatrix}n\ k end{bmatrix}) 轮换与排列是一一对应的(其实一个排列类似一个置换)。


    (x^{overline n}=sumlimits_{k} egin{bmatrix}n\ k end{bmatrix} x^k ,ngeq 0)

    (x^{underline n}= sumlimits_{k} egin{bmatrix}n\ k end{bmatrix} (-1)^{n-k} x^k ,ngeq 0)

    求解

    求解(egin{bmatrix}n\ k end{bmatrix})

    由于(x^{overline n}=sumlimits_{k=0}^negin{bmatrix}n\ kend{bmatrix} x^k) ,所以我们可以直接通过分治FFT求(x^{overline n})(mathcal{O}(nlog^2n)) 求出。

    优化:

    当我们求完(x^{overline n}) 后,如果可以直接求出((x+n)^{overline n}) ,那么可以直接得出(x^{overline{2n}}) ,时间复杂度则降为(T(n)=T(frac{n}{2})+mathcal{O}(nlog n)=mathcal{O}(nlog n))

    (x^{overline n}=sumlimits_{k=0}^n a_ix^i)

    (egin{aligned}(x+n)^{overline n}&=sum_{i=0}^n a_i(x+n)^i\&=sum_{i=0}^n a^i sum_{j=0}^i {i choose j}x^j n^{i-j} \&=sum_{i=0}^n x^i sum_{j=i}^n {j choose i} a^j n^{j-i}\&=sum_{i=0}^nfrac{x^i}{i!}sum_{j=i}^nfrac{n^{j-i}}{(j-i)!} j!a_j end{aligned})

    后面的部分是一个减法卷积,我们可以反转其中一个变成加法卷积即可。

    P5408 【模板】第一类斯特林数·行

    #include<iostream>
    #include<cstdio>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    const int N=530000,G=3,Gi=55924054,M=167772161;
    inline int qpow(int a,int b) { R ret=1;
      for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
    }
    int n,K,len,p[N],fac[N],ifac[N];
    inline void init(int n) {
      K=1,len=0; while(K<=n) K<<=1,++len;
      for(R i=1;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
    }
    inline void ntt(int* a,int op) {
      for(R i=1;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
      for(R l=1;l<K;l<<=1) {
        R w1=qpow(~op?G:Gi,(M-1)/(l<<1)),wn,x,y;
        for(R len=l<<1,i=0;i<K;i+=len) { wn=1;
          for(R j=0;j<l;++j,wn=1ll*w1*wn%M)
            x=a[i+j],y=1ll*a[i+j+l]*wn%M,a[i+j]=(x+y)%M,a[i+j+l]=(x-y+M)%M;
        } 
      } if(~op) return ; R Inv=qpow(K,M-2);
      for(R i=0;i<K;++i) a[i]=1ll*a[i]*Inv%M;
    }
    int f[N],a[N],b[N],ta[N],tb[N];
    inline void calc(const int* f,int n,int* h) {
      init(n<<1);
      for(R i=0;i<=n;++i) ta[n-i]=1ll*f[i]*fac[i]%M;
      for(R t=1,i=0;i<=n;++i,t=1ll*t*n%M) 
        tb[i]=1ll*ifac[i]*t%M;
      for(R i=n+1;i<K;++i) ta[i]=tb[i]=0;
      ntt(ta,1),ntt(tb,1);
      for(R i=0;i<K;++i) ta[i]=1ll*ta[i]*tb[i]%M;
      ntt(ta,-1);
      for(R i=0;i<=n;++i) h[i]=1ll*ta[n-i]*ifac[i]%M;
    } 
    inline void solve(int n,int* f) {
      if(n==0) return ;
      R md=n>>1;
      solve(md,f);
      calc(f,md,a);
      init(n);
      for(R i=0;i<=md;++i) b[i]=f[i];
      for(R i=md+1;i<K;++i) a[i]=b[i]=0;
      ntt(a,1),ntt(b,1);
      for(R i=0;i<K;++i) a[i]=1ll*a[i]*b[i]%M;
      ntt(a,-1);
      if(n&1) for(R i=0;i<=n;++i) 
        f[i]=((i?a[i-1]:0)+1ll*(n-1)*a[i])%M;
      else for(R i=0;i<=n;++i) f[i]=a[i];
    }
    inline void main() {
      scanf("%d",&n); 
      f[0]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
      for(R i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%M;
      ifac[n]=qpow(fac[n],M-2);
      for(R i=n-1;i>=2;--i) ifac[i]=1ll*ifac[i+1]*(i+1)%M;
      solve(n,f);
      for(R i=0;i<=n;++i) 
        printf("%d ",f[i]);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    第二类斯特林数

    (egin{Bmatrix}n\ k end{Bmatrix}) 表示(n) 个有区别的元素划分成(k) 个非空子集的方案数。

    (egin{Bmatrix}0\ 0 end{Bmatrix}=1)

    (egin{Bmatrix}n\ 0 end{Bmatrix}=0 ,ngeq 1)

    (egin{Bmatrix}n\ 1 end{Bmatrix}=1 ,ngeq 1)

    (egin{Bmatrix}n\ 2 end{Bmatrix}=2^{n-1}-1 ,ngeq 1) 强制至少一个元素在集合(A) ,剩下(2^{n-1}) 种方案,减去集合(B) 是空集的方案。

    (egin{Bmatrix}n\ 0 end{Bmatrix}=0 ,ngeq 1)

    (egin{Bmatrix}n\ k end{Bmatrix}=kegin{Bmatrix}n-1\ k end{Bmatrix}+egin{Bmatrix}n-1\ k-1 end{Bmatrix} ,ngeq 1)

    (egin{Bmatrix}n\ n end{Bmatrix} = 1 ,egin{Bmatrix}n\ n-1 end{Bmatrix} = {n choose 2})

    性质

    (x^{n}=sumlimits_{k} egin{Bmatrix}n\ k end{Bmatrix} x^{underline k} ,ngeq 0)

    (x^{n}= sumlimits_{k} egin{Bmatrix}n\ k end{Bmatrix} (-1)^{n-k} x^{overline k} ,ngeq 0)

    顺带:(x^{overline n}=(-1)^n(-x)^{underline n},x^{underline n}=(-1)^n(-x)^{overline n})


    (x^n=sumlimits_{k=0}^x egin{Bmatrix}n\ k end{Bmatrix} k!{x choose k}) ,即(x^n=sumlimits_{k=0}^x egin{Bmatrix}n\ k end{Bmatrix} imes x^{underline k})

    (x^n)(n) 个有区别的小球丢进(x) 个有区别的盒子,允许空盒子;枚举有效盒子的个数,再从(x) 个盒子选(k) 个盒子,然后(n) 个小球丢进(k) 个盒子。


    (m^n=sumlimits_{i=0}^{m}egin{Bmatrix}n\ iend{Bmatrix}i!{m choose i})

    二项式反演一下:

    (m!egin{Bmatrix}n\ mend{Bmatrix}=sumlimits_{k=0}^m(-1)^{k} {mchoose k}(m-k)^n)

    理解:如果空箱子的情况我们也算进去,答案显然是(frac{m^n}{m!}) ;反过来求第二类斯特林数,又得减掉这种情况:

    • (k) 个空盒子,然后小球放到其他的盒子里
    • 但最后我们求出来的答案为有区别的盒子,转换过来要( imes frac{1}{m!})

    求解

    求解(egin{Bmatrix}n\ k end{Bmatrix})

    (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})

    发现可以卷积求出(n) 一行的斯特林数。

    P5395 【模板】第二类斯特林数·行

    #include<iostream>
    #include<cstdio>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
      register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
      do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
    } const int N=800010,G=3,Gi=55924054,M=167772161;
    int n,K,len,ans;
    int fac[N],Inv[N],a[N],b[N],p[N];
    inline int qpow(int a,int b) { R ret=1;
      for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
    }
    inline void ntt(int* a,int op) {
      for(R i=0;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
      for(R l=1;l<K;l<<=1) { R g1=qpow(~op?G:Gi,(M-1)/(l<<1)),gn,x,y;
        for(R len=l<<1,i=0;i<K;i+=len) { gn=1;
          for(R j=0;j<l;++j,gn=1ll*gn*g1%M) 
            x=a[i+j],y=1ll*a[i+j+l]*gn%M,a[i+j]=(x+y)%M,a[i+j+l]=(x-y+M)%M;
        }
      }
    }
    inline void main() {
      n=g();
      fac[0]=fac[1]=Inv[0]=Inv[1]=1;
      for(R i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%M;
      Inv[n]=qpow(fac[n],M-2);
      for(R i=n-1;i>=2;--i) Inv[i]=1ll*Inv[i+1]*(i+1)%M;
      K=1; while(K<=n*2) K<<=1,++len;
      for(R i=0;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
      for(R i=0;i<=n;++i) a[i]=1ll*(i&1?M-1ll:1ll)*Inv[i]%M;
      for(R i=0;i<=n;++i) b[i]=1ll*qpow(i,n)*Inv[i]%M;
      ntt(a,1),ntt(b,1); 
      for(R i=0;i<K;++i) a[i]=1ll*a[i]*b[i]%M;
      ntt(a,-1); R inv=qpow(K,M-2);
      for(R i=0;i<=n;++i) a[i]=1ll*a[i]*inv%M;
      for(R i=0;i<=n;++i) printf("%d ",a[i]);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    与自然数幂的关系

    (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}^n{ichoose j}\ &=sumlimits_{j=0}^k egin{Bmatrix}k\ j end{Bmatrix}j!{n+1 choose j+1}\ &=sumlimits_{j=0}^k egin{Bmatrix}k\ j end{Bmatrix} frac{(n+1)^{underline {j+1}}}{j+1}end{aligned})


    斯特林反演

    [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) ]

    反转公式

    (sumlimits_{k=m}^n (-1)^{n-k}egin{bmatrix}n\ kend{bmatrix} egin{Bmatrix}k\ mend{Bmatrix}=[m=n]\ sumlimits_{k=m}^n (-1)^{n-k}egin{Bmatrix}n\ kend{Bmatrix} egin{bmatrix}k\ mend{bmatrix}=[m=n])

    证明:

    (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})

    (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})

  • 相关阅读:
    Python模块:struct
    Python模块:hashlib
    Python模块:collections
    python:爬虫
    Python:进程
    Python:线程
    Python:socket
    Welcome to ARFA's cnblog ! (Click me)
    骗访问量的机房人物列传by xMinh
    关于我
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12194232.html
Copyright © 2011-2022 走看看