ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

典中典之第二类斯特林数

2022-08-11 01:01:39  阅读:150  来源: 互联网

标签:第二类 frac 斯特林 sum int 典中典 binom underline Mod


第二类斯特林数:将 \(n\) 个物品放进 \(m\) 个不区分的盒子的方案数,记为 \(S(n,m)\)。

\(n^2\) 递推公式:\(S(n,m)=S(n-1,m-1)+m\cdot S(n-1,m)\).

附代码:

s[0][0]=1;
for(int i=1;i<=n;++i)
    for(int j=1;j<=i;++j)
        s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));

第二类斯特林数的卷积公式:

\[S(n,m)=\sum_{k=0}^m \frac{(-1)^k}{k!}\frac{(m-k)^n}{(m-k)!} \]

斯特林数转下降幂公式:

\[x^k=\sum_{i=0}^kS(k,i)x^{\underline i} \]

又已知一常见组合公式(证明展开即可):

\[\binom{n}{x} x^{\underline i}=\binom{n-i}{x-i}n^{\underline i} \]

将以上两式合并则有:

\[\binom{n}{x}x^k = \sum_{i=0}^k S(k,i)\binom{n-i}{x-i} n^{\underline i} \]

对于枚举 \(x\) 的题目,一般只需交换求和号后将后面的组合数用二项式定理合并成 \(n-i\) 次多项式即可,这样可以将时间复杂度由 \(n\) 降到 \(k\)。

例1:CF932E Team Work

从 \(n\) 个物品中挑任意个,挑 \(x\) 个的价值为 \(x^k\)。求所有方案的价值和。\(n\le 10^9, k\le 5000\).

即求

\[\sum_{x=0}^n \binom{n}{x} x^k \]

由前文式子可得

\[=\sum_{x=0}^n \sum_{i=0}^k S(k,i)\binom{n-i}{x-i} n^{\underline i} \]

交换求和号

\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=i}^{n} \binom{n-i}{x-i} \]

改为枚举 \(x-i\)

\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=0}^{n-i} \binom{n-i}{x} \]

后半部分求和用二项式定理合并,即为

\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i} 2^{n-i} \]

\(O(k^2)\) 预处理第二类斯特林数后 \(O(k)\) 求解即可。

#include<bits/stdc++.h>
using namespace std;
const int N=5005,Mod=1e9+7;
#define mul(x,y) (1ll*(x)*(y)%Mod)
inline int add(int x, int y)
{
    return (x+y>=Mod?x+y-Mod:x+y);
}
inline int po(int x, long long y)
{
    int r=1;
    for(;y;y>>=1,x=mul(x,x)) if(y&1) r=mul(r,x);
    return r;
}
int s[N][N],n,m,k;
int main()
{
    int n,k; scanf("%d%d",&n,&k);
    s[0][0]=1;
    for(int i=1;i<=k;++i)
        for(int j=1;j<=i;++j)
            s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
    int ans=0;
    for(int i=0,b=1,c=po(2,n),iv=po(2,Mod-2);i<=min(n,k);++i)
    {
        int t=mul(s[k][i],mul(b,c));
        ans=add(ans,t);
        b=mul(b,n-i), c=mul(c,iv);
    }
    printf("%d\n",ans);
}

例2:CF1716F Bags with Balls

有 \(n\) 个盒子,每个盒子里放着编号 \(1\sim m\) 的球。每次从每个盒子里分别抽取 1 个球,令抽到的编号为奇数的球的个数为 \(x\),则价值为 \(x^k\)。求所有可能方案的价值之和。\(T\) 组数据,\(n,m<998244353, k\le 2000\).

即为求

\[\sum_{x=0}^n x^k \binom{n}{x} \lceil\frac{m}{2}\rceil^x \lfloor \frac{m}{2}\rfloor ^ {n-x} \]

由上文结论易推得

\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i}\sum_{x=0}^{n-i} \binom{n-i}{x} \lceil\frac{m}{2}\rceil^{x+i} \lfloor \frac{m}{2}\rfloor ^ {n-i-x} \]

提取一个 \(\lceil\frac{m}{2}\rceil^i\),后面用二项式定理合并,即为 \(m^{n-i}\)。

\[=\sum_{i=0}^{\min(k,n)} S(k,i)n^{\underline i} \lceil\frac{m}{2}\rceil^i m^{n-i} \]

线性计算即可。复杂度 \(O(k^2+Tk)\)。

#include<bits/stdc++.h>
using namespace std;
const int N=2022,Mod=998244353;
#define mul(x,y) (1ll*(x)*(y)%Mod)
inline int add(int x, int y)
{
    return (x+y>=Mod?x+y-Mod:x+y);
}
inline int po(int x, long long y)
{
    int r=1;
    for(;y;y>>=1,x=mul(x,x)) if(y&1) r=mul(r,x);
    return r;
}
int s[N][N],n,m,k;
void Init()
{
    const int n=2000;
    s[0][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=i;++j)
            s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
}
int main()
{
    Init();
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        const int o=(m-1)/2+1;
        int ans=0;
        for(int i=0,b=1,c=1,d=po(m,n),iv=po(m,Mod-2);i<=min(n,k);++i)
        {
            int t=mul(s[k][i],mul(mul(b,c),d));
            ans=add(ans,t);
            b=mul(b,n-i), c=mul(c,o), d=mul(d,iv);
        }
        printf("%d\n",ans);
    }
}

待填坑。

标签:第二类,frac,斯特林,sum,int,典中典,binom,underline,Mod
来源: https://www.cnblogs.com/farway17/p/16574471.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有