码迷,mamicode.com
首页 > 其他好文 > 详细

Stirling数

时间:2019-05-04 23:45:21      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:gen   wap   get   ++   for   范围   rac   www   int   

第一类\(Stirling\)

\(\begin{bmatrix} n \\ m \\ \end{bmatrix}\)表示\(n\)个元素组成\(m\)个圆排列的方案数。

何为圆排列?即通过排列在一个环上,两两不能通过旋转相互得到的排列的个数。
\[ \begin{bmatrix} n \\ m \\ \end{bmatrix}=\begin{bmatrix} n-1 \\ m-1 \\ \end{bmatrix}+(n-1)\cdot \begin{bmatrix} n-1 \\ m \\ \end{bmatrix} \]
\[ \begin{bmatrix} 0 \\ 0 \\ \end{bmatrix}=1, \begin{bmatrix} n \\ 0 \\ \end{bmatrix}=0(n>0) \]

递推考虑加入的元素要不重新成一个排列,要不放在已有的任一个元素后。

性质
\[ (n-1)!=\begin{bmatrix} n \\ 1 \\ \end{bmatrix} \]
圆排列性质
\[ n!=\sum_{i=0}^{n}\begin{bmatrix} n \\ i \\ \end{bmatrix} \]
置换与圆排列关系
\[ \begin{bmatrix} n \\ 2 \\ \end{bmatrix}=(n-1)!\cdot \sum_{i=1}^{n-1}\frac{1}{i} \]

\[ \begin{bmatrix} n \\ n-1 \\ \end{bmatrix}=\begin{pmatrix} n \\ 2 \\ \end{pmatrix} \]

\[ \begin{bmatrix} n \\ n-2 \\ \end{bmatrix}=2\begin{pmatrix} n \\ 3 \\ \end{pmatrix}+3\begin{pmatrix} n \\ 4 \\ \end{pmatrix} \]

一些其他的性质
\[ x^{\overline{n}}=\sum_{i=0}^{n} \begin{bmatrix} n \\ i \\ \end{bmatrix} x^{i} \]

\[ x^{\underline{n}}=\sum_{i=0}^{n}\begin{bmatrix} n \\ i \\ \end{bmatrix}(-1)^{n-i}x^i \]

两个与上升幂与下降幂有关的性质。

上述性质大多可以用数学归纳法证明,限于篇幅,不给出具体证明。

求解第一类\(Stirling\)

我们有\(O(nlog^2n)\)的分治\(NTT\)做法
\[ \sum_{i=0}^{n}\begin{bmatrix} n \\ i \\ \end{bmatrix}x^i=\prod_{i=0}^{n-1}(x+i) \]
记生成函数为\(f_n=\prod_{i=0}^{n-1}(x+i)\),可以得到:
\[ f_n=(x+n-1)f_{n-1}=xf_{n-1}+(n-1)f_{n-1} \]
这个和第一类\(Stirling\)数的递推式等价。

一道经典例题

求长度为\(n\)的排列中从左边能看到\(A\)个且从右边能看到\(B\)个的数量。(能看到即为前缀/后缀最大值)

按最高的楼分为两部分,左边有\(A-1\)个,右边有\(B-1\)个要被看见,这\(A+B-2\)个都要放在靠边的位置,所以方案数是圆排列(固定了一个为第一个),即\(\begin{bmatrix} n-1 \\ A+B-2 \\ \end{bmatrix}\)

然后选\(A-1\)个放左边,总方案数为\(\begin{bmatrix} n-1 \\ A+B-2 \\ \end{bmatrix}\cdot \begin{pmatrix} A+B-2 \\ A-1 \\ \end{pmatrix}\)

一个双倍经验题

和上题除数据范围外都一致,用分治\(NTT\)的方式求第一类\(Stirling\)数即可。

给出后面一题的代码

//by OIerC
//Forca Barcelona!
#include<cstdio>
#include<algorithm>
#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
using namespace std;
const int N=400005, P=998244353, G=3;
inline int add(int x, int y){return x+y>=P?x+y-P:x+y;}
inline int sub(int x, int y){return x-y<0?x-y+P:x-y;}
inline int mul(int x, int y){return 1ll*x*y-1ll*x*y/P*P;}
int S[20][N], rev[N], n, A, B;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}

int Pow(int x, int t)
{
    int res=1;
    for (; t; t>>=1, x=mul(x, x)) if (t&1) res=mul(res, x);
    return res;
}

int C(int n, int m)
{
    int ans=1;
    rep(i, n-m+1, n) ans=mul(ans, i);
    rep(i, 1, m) ans=mul(ans, Pow(i, P-2));
    return ans;
}

void NTT(int *a, int n, int x)
{
    for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i], a[rev[i]]);
    for (int mid=1, len=2; mid<n; mid<<=1, len<<=1)
    {
        int Gn=Pow(G, (P-1)/len);
        for (int i=0; i<n; i+=len)
        {
            int Gen=1;
            for (int j=0; j<mid; j++, Gen=mul(Gen, Gn))
            {
                int A1=a[i+j], A2=mul(Gen, a[i+j+mid]);
                a[i+j]=add(A1, A2); a[i+j+mid]=sub(A1, A2);
            }
        }
    }
    if (!~x)
    {
        reverse(a+1, a+n);
        int inv=Pow(n, P-2);
        for (int i=0; i<n; i++) a[i]=mul(a[i], inv);
    }
}

void solve(int l, int r, int deg)
{
    if (l==r) {S[deg][0]=l; S[deg][1]=1; return;}
    int mid=l+r>>1, lim=1, cnt=0;
    while (lim<=r-l+1) lim<<=1, cnt++;
    solve(l, mid, deg+1);
    rep(i, 0, mid-l+1) S[deg][i]=S[deg+1][i];
    solve(mid+1, r, deg+1);
    rep(i, mid-l+2, lim) S[deg][i]=0;
    rep(i, r-mid+1, lim) S[deg+1][i]=0;
    rep(i, 0, lim-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(cnt-1));
    NTT(S[deg], lim, 1); NTT(S[deg+1], lim, 1);
    rep(i, 0, lim-1) S[deg][i]=mul(S[deg][i], S[deg+1][i]);
    NTT(S[deg], lim, -1);
}

int main()
{
    n=read(); A=read(); B=read();
    if (n-1<A+B-2 || !A || !B) {puts("0"); return 0;}
        else if (n==1) {puts("1"); return 0;}
    solve(0, n-2, 0);
    printf("%d\n", mul(C(A+B-2, A-1), S[0][A+B-2]));
    return 0;
}

第二类\(Stirling\)

【占坑待填】

Stirling数

标签:gen   wap   get   ++   for   范围   rac   www   int   

原文地址:https://www.cnblogs.com/ACMSN/p/10810418.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!