首页 > 其他 > 详细

wsoj「G2016 SCOI2018 Round #12」建筑师

时间:2018-01-07 22:44:56      阅读:266      评论:0      收藏:0      [点我收藏+]

传送门

小半个月前的测试,现在翻出来。

考试时我和sxyA了这题。

当时随便搞了个dp,dp[i][j]表示i个数能看到j个的情况数,考虑新加入一个比之前i-1个数都小的数,能看到它的情况是它加到第一个,不能看到它的情况是它加到第1~i-1个数之后。所以 dp[i][j]=dp[i-1][j-1]*1+dp[i-1][j]*(i-1);

然而这个东西刚好就是第一类斯特林数。

第一类Stirling数是有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目。

i个数的排列可以看到j个数的情况可以看作 把i个数分成j个集合,每个集合中最大的数排在第一个,其它的数任意排列。而这刚好是一个环排列。

显然,n个数的环排列等于n-1个数的全排列。

技术分享图片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
const int N=5e4+7;
const int mod=1e9+7;
typedef long long LL;
using namespace std;
LL dp[N][207],C[207][207];
int T,n,a,b;

template<typename T> void read(T &x) {
    char ch=getchar(); T f=1; x=0;
    while(ch!=-&&(ch<0||ch>9)) ch=getchar();
    if(ch==-) f=-1,ch=getchar();
    for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
}

#define orzllj
int main() {
#ifdef orzllj
    freopen("building.in","r",stdin);
    freopen("building.out","w",stdout);
#endif
    dp[1][1]=1;
    for(int i=2;i<=50000;i++) 
        for(int k=1;k<=min(200,i);k++) 
            dp[i][k]=(dp[i-1][k]*(i-1)%mod+dp[i-1][k-1])%mod;
    for(int i=0;i<=200;i++) C[i][0]=1;
    for(int i=1;i<=200;i++)
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    read(T);
    while(T--) {
        read(n); read(a); read(b);
        LL ans=dp[n-1][a+b-2];
        ans=(ans*C[a+b-2][a-1])%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
/*
2
3 2 2
3 2 1
*/
View Code

 

顺便:

第二类Stirling数实际上是集合的一个拆分,表示将n个不同的元素拆分成m个集合的方案数,

S(n,k)=s(n-1,k-1)+S(n-1,k)*k;   递推公式很好想。

通项公式:

技术分享图片

 

其它的之后什么时候再学吧。

 

wsoj「G2016 SCOI2018 Round #12」建筑师

原文:https://www.cnblogs.com/Achenchen/p/8231366.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!