斯特林数-离散微积分学习笔记

89 篇文章 0 订阅
72 篇文章 0 订阅

一、定义

1.第一类斯特林数:

表示方法:S1(n,m)或 [ n m ] n \brack m [mn]
组合意义:指n个点组成m个圆排列的方案数。
递推求法:S1(n,m)=S1(n-1,m-1)+(n-1)*S1(n-1,m)
快速求法:
∏ i = 0 n − 1 ( x + i ) \prod_{i=0}^{n-1}(x+i) i=0n1(x+i)
的第k次项系数就是S1(n,k),所以可用分治fft做到n*log^2或者再推下用倍增fft做到n*log

2.第二类斯特林数

表示方法:S2(n,m)或 \{ n m \} n \brace m {mn}
组合意义:指n个点划分成m个非空集合的方案数。
递推求法:S2(n,m)=S2(n-1,m-1)+m*S2(n-1,m)
快速求法:考虑枚举至少i个集合是空的,容斥所求的0个集合非空得:
S 2 ( n , m ) = 1 m ! ∑ i = 0 m ( − 1 ) i ∗ ( m i ) ∗ ( m − i ) n S2(n,m)=\frac{1}{m!}\sum_{i=0}^m(-1)^i*\binom m i*(m-i)^n S2(n,m)=m!1i=0m(1)i(im)(mi)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
x k = ∑ i = 0 k ( x i ) ∗ \{ k i \} ∗ i ! = ∑ i = 0 k x i ‾ ∗ \{ k i \} x^k=\sum_{i=0}^{k}\binom x i*{k\brace i}*i!=\sum_{i=0}^{k}x^{\underline i}*{k\brace i} xk=i=0k(ix){ik}i!=i=0kxi{ik}
理解:x种颜色给k个点染色,直接考虑是等式左边,复杂地考虑用上k种颜色的方案数求和就是等式右边了。枚举到k是因为用的颜色数不会多于点数,而且推式子题目k也一般比x范围小。
x k ‾ = ∑ i = 0 k [ k i ] ∗ x i x^{\overline k}=\sum_{i=0}^{k}{k\brack i}*x^i xk=i=0k[ik]xi
理解:k个点组成圆排列,在为每个圆排列里的所有点染一种颜色。等式右边意义为暴枚组成了几个圆排列计算,左边意义为:考虑一个个加入点,对于当前点可以染x种颜色任意一种或者放到某个点左边并和这个点颜色相同,那么显然就是 x k ‾ x^{\overline k} xk

而下降幂与上升幂有如下转化:
x n ‾ = ( − 1 ) n ( − x ) n ‾ x n ‾ = ( − 1 ) n ( − x ) n ‾ x^{\underline{n}}=(-1)^n(-x)^{\overline{n}}\\ x^{\overline{n}}=(-1)^n(-x)^{\underline{n}} xn=(1)n(x)nxn=(1)n(x)n
所以之前两个东西可以互相带来带去得出一堆等式…(推详见参考的大佬博客)
斯特林反演:
f ( n ) = ∑ k = 0 n { n k } g ( k ) ⟺ g ( n ) = ∑ k = 0 n ( − 1 ) n − k [ n k ] 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) f(n)=k=0n{nk}g(k)g(n)=k=0n(1)nk[nk]f(k)
之后是一个很重要的东西(推式子方法很有用):
首先要理解"差分"这个东西的真正意义(原来以为就是一个数组后一项减前一项…),它的别名叫离散微分,就是说把微积分里的无限小变成1,求导的
lim ⁡ d x → 0 f ( x + d x ) − f ( x ) d x \lim_{dx \rightarrow 0} \frac{f(x+dx)-f(x)}{dx} dx0limdxf(x+dx)f(x)
这个式子里的 d x → 0 dx \rightarrow 0 dx0变成 d x = 1 dx =1 dx=1
那么这样可导的条件也不是函数连续,而是离散意义下的连续了。
还有一些积分之类符号的变化,可以参见参考的第三篇大佬博客
可以发现这样能得到
Δ x k ‾ = k ∗ x k − 1 ‾ \Delta x^{\underline k}=k*x^{\underline {k-1}} Δxk=kxk1
几乎就等于原来对 x k x^k xk求导了.
把k用k+1代可以得到 x k ‾ x^{\underline k} xk原函数为:
x k + 1 ‾ k + 1 \frac {x^{\underline {k+1}}}{k+1} k+1xk+1(ps:这里分母的k+1要看成一个常数而不是关于k的变量)

而根据前面得到幂级数和下降幂之间的通过斯特林数的关系式,发现 x k x^k xk差分也能得到了。
来推下一个较常出现的东西–自然数幂和(先推n-1好化简一点)
f ( n − 1 ) = ∑ i = 0 n − 1 i k = ∑ i = 0 n − 1 ∑ j = 0 k \{ k j \} i j ‾ = ∑ j = 0 k \{ k j \} ∑ i = 0 n − 1 i j ‾ = ∑ j = 0 k \{ k j \} ∑ i = 0 n − 1 Δ i j + 1 ‾ j + 1 = ∑ j = 0 k \{ k j \} n j + 1 ‾ j + 1 f ( n ) = ∑ j = 0 k \{ k j \} ( n + 1 ) j + 1 ‾ j + 1 = ( n + 1 ) ∑ j = 0 k \{ k j \} n j ‾ j + 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}\\ f(n1)=i=0n1ik=i=0n1j=0k{jk}ij=j=0k{jk}i=0n1ij=j=0k{jk}j+1i=0n1Δij+1=j=0k{jk}j+1nj+1f(n)=j=0k{jk}j+1(n+1)j+1=(n+1)j=0k{jk}j+1nj
复杂度就是瓶颈就在求斯特林数上了。

再来推道cf的题目:
http://codeforces.com/problemset/problem/932/E
∑ i = 0 n ( n i ) i k = ∑ i = 0 n ( n i ) ∑ j = 0 k \{ k j \} ( i j ) j ! = ∑ i = 0 n n ! ( n − i ) ! ∑ j = 0 k \{ k j \} 1 i − j = ∑ j = 0 k \{ k j \} ∑ i = 0 n n ! ( n − i ) ! ∗ 1 ( i − j ) ! = ∑ j = 0 k \{ k j \} ∗ n ! ( n − j ) ! ∑ i = 0 n ( n − j i − j ) = ∑ j = 0 k \{ k j \} ∗ n j ‾ ∗ 2 n − j \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=0n(in)ik=i=0n(in)j=0k{jk}(ji)j!=i=0n(ni)!n!j=0k{jk}ij1=j=0k{jk}i=0n(ni)!n!(ij)!1=j=0k{jk}(nj)!n!i=0n(ijnj)=j=0k{jk}nj2nj

个人觉得刚开始推这种题目难想的就是如何把有关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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值