counting the buildings - 第一类斯特灵数

2017-08-10 21:10:08

writer:pprp

//TLE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
typedef long long ll;
const int maxn = 2020;

ll dp[maxn][maxn];

const int mod = 1e9 + 7;

void S1()
{
    for(int i = 1 ; i <= 20 ; i++)
    {
        dp[i][0] = 0;
        dp[i][i] = 1;
        for(int j = 1; j < i ; j++)
            dp[i][j] = (i - 1) * dp[i-1][j] + dp[i-1][j-1];
    }
}

//a^b%m 快速幂
int quick_power_mod(int a, int b, int m)
{
    int result = 1;
    int base = a;
    while(b > 0)
    {
        if(b&1 == 1)//如果b是奇数
        {
            result = (result * base) % m;
        }
        base = (base * base)%m;
        b>>=1;
    }
    return result;
}

//组合数取模 C(a,b)%p
ll composition(ll a, ll b, int p)
{
    if(a < b)
        return 0;
    if(a == b)
        return 1;
    if(b > a - b) b = a - b;

    int ans = 1, ca  = 1, cb = 1;
    for(ll i = 0 ; i < b; i++)
    {
        ca = (ca * (a - i))%p;
        cb = (cb * (b - i))%p;
    }

    ans = (ca * quick_power_mod(cb,p - 2, p)) % p;
    return ans;
}

ll lucas(ll n, ll m, ll p)
{
    ll ans = 1;
    while(n && m && ans)
    {
        ans = (ans * composition(n%p, m%p, p))%p;
        n /= p;
        m /= p;
    }
    return ans;
}

int main()
{
    S1();
    int T;
    cin >> T;
    int N, F, B;

    while(T--)
    {
        cin >> N >> F >> B;
        cout << dp[N-1][F+B-2]*composition(F+B-2,F-1,mod) <<endl;
    }
    return 0;
}

标解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
typedef long long ll;
const int maxn = 2020;

ll dps[maxn][maxn];
ll dpc[maxn][maxn];

const ll mod = 1e9 + 7;

 void init()
 {
       for(int i = 0; i < maxn ; i++)
       {
             dpc[i][0] = dpc[i][i] = dps[i][i] = 1;
             for(int j = 1; j < i ; j++)
             {
                   dpc[i][j] = (dpc[i-1][j-1]+dpc[i-1][j])%mod;
                   dps[i][j] = ((i-1)*dps[i-1][j])%mod + dps[i-1][j-1]%mod;
             }
       }
 }

int main()
{
    int T;
    cin >> T;
    long long N, F, B;
    init();

    while(T--)
    {
        cin >> N >> F >> B;
        cout << dps[N-1][F+B-2]*dpc[F+B-2][F-1]%mod <<endl;
    }
    return 0;
}

标解中组合数是用杨辉三角求解的

杨辉三角dp法

dp[i][j]=dp[i-1][j-1]+dp[i-1][j]

O(n^2)~O(1)

时间: 2024-08-05 19:35:23

counting the buildings - 第一类斯特灵数的相关文章

Examining the Rooms - 第一类斯特灵数

---恢复内容开始--- 2017-08-10 20:32:37 writer:pprp 题意如下: Recently in Teddy's hometown there is a competition named "Cow Year Blow Cow".N competitors had took part in this competition.The competition was so intense that the rank was changing and changi

hdu 2521 一卡通大冒险 (斯特灵数,贝尔数)

/* 将N张卡分成若干个集合,集合不为空,有多少种分法. f[n][m]表示n张卡分成m组的种类数,那么f[n][m]=f[n-1][m-1]+f[n-1][m]*m,//第二类斯特灵数 而ans[n]=sum{f[n][l]}(1<=l<=m).//ans为贝尔数,Bell数是将P个元素集合分到非空且不可区分例子的划分个数. 其中:f[n-1][m-1]代表第n个人自成一堆: f[n-1][m]*m代表第n个人不自成一堆. */ # include <stdio.h> # inc

HDU2512 一卡通大冒险【斯特灵数,贝尔数】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2512 题目大意: 有N张卡,将N张卡分成若干不同的集合,集合不能为空.问:总共有多少种分法. 思路: 参考博文:http://blog.csdn.net/acm_cxlove/article/details/7857671 集合的个数可以为1.2.3.-.N.问题就变为了把N张卡放到i个集合中. 这时候个组合问题,可以用第二类斯特灵数解决. S(P,K) = S(P-1,K-1) + K*S(P-

UVA 10844 - Bloques (第二类斯特灵数)

UVA 10844 - Bloques 题目链接 题意:给定n个数字,问这n个数字能分成子集分成有几种分法 思路:一开始先想了个状态,dp[i][j]表示放i个数字,分成j个集合的方案,那么转移为,从dp[i - 1][j - 1]在多一个集合,和从dp[i - 1][j]有j个位置放,那么转移方程为dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] * j;按理说这个状态转移是没问题的,但是由于这题答案是高精度,n为900时答案高达1700多位,加上高精度运算

挑战程序设计竞赛 划分数,贝尔数,斯特灵数

斯特灵数:把n个数划分为恰好k个非空集合的个数,记为S(n,k).且有:S(n,1)=S(n,n)=1. 有递推关系式: S(n+1,k)=S(n,k?1)+kS(n,k?1) 贝儿数:把n个数划分为非空集合的所有划分数.有: Bn=∑i=0nS(n,i) 贝尔数的递推公式: Bn=∑k=0n(nk)Bk 书上的划分数:书上求的是:把n个相同的数划分为不超过m个集合的方法总数.由于这n个数是相同的,就不能算作∑ki=0S(n,i).书上给了这样一个dp的转移方程(定义dp[i][j]为j个数的i

弗罗贝尼乌斯範数(Frobenius norm)

弗罗贝尼乌斯範数 对 p = 2,这称为弗罗贝尼乌斯範数(Frobenius norm)或希尔伯特-施密特範数( Hilbert–Schmidt norm),不过后面这个术语通常只用于希尔伯特空间.这个範数可用不同的方式定义: 这里 A* 表示 A 的共轭转置,σi 是 A 的奇异值,并使用了迹函数.弗罗贝尼乌斯範数与 Kn 上欧几里得範数非常类似,来自所有矩阵的空间上一个内积. 弗罗贝尼乌斯范範数是服从乘法的且在数值线性代数中非常有用.这个範数通常比诱导範数容易计算.

【阿姆斯壮数 】

/* 阿姆斯壮数 说明: 在三位的整数中,例如153可以满足1^3 + 5^3 + 3^3 = 153,这样的数称之为Armstrong数,试写出一程式找出所有的三位数Armstrong数. 解法: Armstrong数的寻找,其实就是在问如何将一个数字分解为个位数.十位数.百位数......,这只要使用除法与余数运算就可以了,例如输入 input 为abc,则: a = input / 100 b = (input%100) / 10 c = input % 10 */ #include <s

Lucas定理 、斯特灵公式

斯特灵公式是一条用来取n阶乘的近似值的数学公式. 公式为: 用该公式我们可以用来估算n阶乘的值:估算n阶乘的在任意进制下的位数. 如何计算在R进制下的位数:我们可以结合对数来计算,比如十进制就是lg(n!)+1,二进制则是log2(n!)+1. Lucas(卢卡斯)定理 公式为:(p为质数) 当然,当n较小时,我们可以用组合数里面的定理来递推求解. 然而当n较大时,显然时间花费很大.而Lucas定理恰好是解决大组合数取模的优解. 在这里由于知识有限,不能完全看懂Lucas定理证明的全部过程.所以

HDU 4372 Count the Buildings(组合数学-斯特林数,组合数学-排列组合)

Count the Buildings Problem Description There are N buildings standing in a straight line in the City, numbered from 1 to N. The heights of all the buildings are distinct and between 1 and N. You can see F buildings when you standing in front of the