斯特林數-離散微積分學習筆記

一、定義

1.第一類斯特林數:

表示方法:S1(n,m)或[nm]n \brack m
組合意義:指n個點組成m個圓排列的方案數。
遞推求法:S1(n,m)=S1(n-1,m-1)+(n-1)*S1(n-1,m)
快速求法:
i=0n1(x+i)\prod_{i=0}^{n-1}(x+i)
的第k次項係數就是S1(n,k),所以可用分治fft做到n*log^2或者再推下用倍增fft做到n*log

2.第二類斯特林數

表示方法:S2(n,m)或\{nm\}n \brace m
組合意義:指n個點劃分成m個非空集合的方案數。
遞推求法:S2(n,m)=S2(n-1,m-1)+m*S2(n-1,m)
快速求法:考慮枚舉至少i個集合是空的,容斥所求的0個集合非空得:
S2(n,m)=1m!i=0m(1)i(mi)(mi)n S2(n,m)=\frac{1}{m!}\sum_{i=0}^m(-1)^i*\binom m i*(m-i)^n
其中之前乘的階乘分之一是因爲後面式子求出的是在盒子有標號(有序)情況下,這樣才能變成無序集合。
顯然搞一搞就是卷積形式可以直接fft來n*log求

二、應用

參考:(Orz)
https://www.cnblogs.com/acha/p/6444944.html
https://www.cnblogs.com/hchhch233/p/10016543.html
http://yyy.is-programmer.com/posts/202122.html
xk=i=0k(xi)\{ki\}i!=i=0kxi\{ki\} x^k=\sum_{i=0}^{k}\binom x i*{k\brace i}*i!=\sum_{i=0}^{k}x^{\underline i}*{k\brace i}
理解:x種顏色給k個點染色,直接考慮是等式左邊,複雜地考慮用上k種顏色的方案數求和就是等式右邊了。枚舉到k是因爲用的顏色數不會多於點數,而且推式子題目k也一般比x範圍小。
xk=i=0k[ki]xi x^{\overline k}=\sum_{i=0}^{k}{k\brack i}*x^i
理解:k個點組成圓排列,在爲每個圓排列裏的所有點染一種顏色。等式右邊意義爲暴枚組成了幾個圓排列計算,左邊意義爲:考慮一個個加入點,對於當前點可以染x種顏色任意一種或者放到某個點左邊並和這個點顏色相同,那麼顯然就是xkx^{\overline k}

而下降冪與上升冪有如下轉化:
xn=(1)n(x)nxn=(1)n(x)n x^{\underline{n}}=(-1)^n(-x)^{\overline{n}}\\ x^{\overline{n}}=(-1)^n(-x)^{\underline{n}}
所以之前兩個東西可以互相帶來帶去得出一堆等式…(推詳見參考的大佬博客)
斯特林反演:
f(n)=k=0n{nk}g(k)g(n)=k=0n(1)nk[nk]f(k) \displaystyle f(n)=\sum_{k=0}^n \begin{Bmatrix}n\\k \end{Bmatrix}g(k) \Longleftrightarrow g(n)=\sum_{k=0}^n(-1)^{n-k}\begin {bmatrix} n\\k \end{bmatrix}f(k)
之後是一個很重要的東西(推式子方法很有用):
首先要理解"差分"這個東西的真正意義(原來以爲就是一個數組後一項減前一項…),它的別名叫離散微分,就是說把微積分裏的無限小變成1,求導的
limdx0f(x+dx)f(x)dx \lim_{dx \rightarrow 0} \frac{f(x+dx)-f(x)}{dx}
這個式子裏的dx0dx \rightarrow 0變成dx=1dx =1
那麼這樣可導的條件也不是函數連續,而是離散意義下的連續了。
還有一些積分之類符號的變化,可以參見參考的第三篇大佬博客
可以發現這樣能得到
Δxk=kxk1\Delta x^{\underline k}=k*x^{\underline {k-1}}
幾乎就等於原來對xkx^k求導了.
把k用k+1代可以得到xkx^{\underline k}原函數爲:
xk+1k+1\frac {x^{\underline {k+1}}}{k+1}(ps:這裏分母的k+1要看成一個常數而不是關於k的變量)

而根據前面得到冪級數和下降冪之間的通過斯特林數的關係式,發現xkx^k差分也能得到了。
來推下一個較常出現的東西–自然數冪和(先推n-1好化簡一點)
f(n1)=i=0n1ik=i=0n1j=0k\{kj\}ij=j=0k\{kj\}i=0n1ij=j=0k\{kj\}i=0n1Δij+1j+1=j=0k\{kj\}nj+1j+1f(n)=j=0k\{kj\}(n+1)j+1j+1=(n+1)j=0k\{kj\}njj+1 f(n-1)=\sum_{i=0}^{n-1}i^k\\ =\sum_{i=0}^{n-1}\sum_{j=0}^{k}{k \brace j}i^{\underline j}\\ =\sum_{j=0}^{k}{k \brace j}\sum_{i=0}^{n-1}i^{\underline j}\\ =\sum_{j=0}^{k}{k \brace j}\frac{\sum_{i=0}^{n-1}\Delta i^{\underline {j+1}}}{j+1}\\ =\sum_{j=0}^{k}{k \brace j}\frac{n^{\underline {j+1}}}{j+1}\\ \\ f(n)=\sum_{j=0}^{k}{k \brace j}\frac{(n+1)^{\underline {j+1}}}{j+1}\\ =(n+1)\sum_{j=0}^{k}{k \brace j}\frac{n^{\underline j}}{j+1}\\
複雜度就是瓶頸就在求斯特林數上了。

再來推道cf的題目:
http://codeforces.com/problemset/problem/932/E
i=0n(ni)ik=i=0n(ni)j=0k\{kj\}(ij)j!=i=0nn!(ni)!j=0k\{kj\}1ij=j=0k\{kj\}i=0nn!(ni)!1(ij)!=j=0k\{kj\}n!(nj)!i=0n(njij)=j=0k\{kj\}nj2nj \sum_{i=0}^n\binom {n} {i} i^k\\ =\sum_{i=0}^n\binom {n}{i} \sum_{j=0}^k{k\brace j}\binom i j j! \\ =\sum_{i=0}^n\frac{n!}{(n-i)!}\sum_{j=0}^k{k\brace j}\frac{1}{i-j} \\ =\sum_{j=0}^k{k\brace j}\sum_{i=0}^n\frac{n!}{(n-i)!}*\frac{1}{(i-j)!}\\ =\sum_{j=0}^k{k\brace j}*\frac{n!}{(n-j)!}\sum_{i=0}^n\binom {n-j}{i-j}\\ =\sum_{j=0}^k{k\brace j}*n^{\underline j}*2^{n-j}\\

個人覺得剛開始推這種題目難想的就是如何把有關i的項強行化成一個可以快速求的東西。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5050;
const ll mod=1e9+7;

ll S2[N][N],jm[N];
ll n,k;

void Ad(ll &x,ll y)
{if((x+=y)>=mod)x-=mod;}
ll qpow(ll x,ll y)
{
    ll res=1;
    while(y)
    {
        if(y&1)res=res*x%mod;
        x=x*x%mod,y>>=1;
    }
    return res;
}

int main()
{
    S2[0][0]=1;
    for(int i=1;i<N;i++)
    {
        for(int j=1;j<=i;j++)
        {
            S2[i][j]=(S2[i-1][j-1]+1LL*j*S2[i-1][j])%mod;
        }
    }
    cin>>n>>k;
    jm[0]=1;
    for(int i=1;i<=k;i++)
        jm[i]=jm[i-1]*(n-i+1)%mod;
    ll ans=0;
    for(int j=0;j<=min(n,k);j++)
        Ad(ans,S2[k][j]*jm[j]%mod*qpow(2,n-j)%mod);
    printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章