HDU - 4372 Count the Buildings 第一类Stirling数

本文探讨了给定N个高度各不相同的房子时,如何根据从两端能看到的房子数量确定这些房子的不同高度排列方式。利用第一类Stirling数和组合数学原理解决了这一问题,并提供了完整的代码实现。

题目链接:

https://vjudge.net/problem/HDU-4372

题目:

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 first building and looking forward, and B buildings when you are behind the last building and looking backward. A building can be seen if the building is higher than any building between you and it. 
Now, given N, F, B, your task is to figure out how many ways all the buildings can be.

Input

First line of the input is a single integer T (T<=100000), indicating there are T test cases followed. 
Next T lines, each line consists of three integer N, F, B, (0<N, F, B<=2000) described above.

Output

For each case, you should output the number of ways mod 1000000007(1e9+7).

Sample Input

2
3 2 2
3 2 1

Sample Output

2
1

题解:

题意:有N个房子在一条直线上,所有房子的高度在1到N之间,并且所有房子的高度都不相同,从左往右看能看到F个房子,从右往左看能看到B个房子,问房子的排列有多少种方案。

   从左往右看能看到F个房子,不算最高为N的那个房子,能看到F-1个房子;

  从右往左看能看到B个房子,不算最高为N的那个房子,能看到B-1个房子;

  那么就能看成是把1到N-1 总共N-1个元素分配到  F-1+B-1个圆排列里,第一类Stirling解决的问题就是 :把n个不同的元素分配到k个圆排列里,圆不能为空的方案数。   求出圆排列的方案数,再乘上C(F+B-2,F-1)就是最后的答案,C(F+B-2,F-1)的意思是从F+B-2个圆排列选F-1放到 高度为N的房子的左边的方案数。能看到的房子就是每个圆排列中最高的那个房子。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2005;
const int mod=1e9+7;
ll c[maxn][maxn],f[maxn][maxn];
void init(){
    c[0][0]=f[0][0]=1;
    for(int i=1;i<=2000;i++){
        c[i][0]=c[i][i]=1;
        f[i][0]=0;f[i][i]=1;
    }
    for(int i=2;i<=2000;i++){
        for(int j=1;j<i;j++){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
            f[i][j]=(f[i-1][j-1]+(i-1)*f[i-1][j])%mod;
        }
    }
}
int main(){
    init();
    int t,n,a,b;
    cin>>t;
    while(t--){
        scanf("%d%d%d",&n,&a,&b);
        if(a+b-2>n) printf("0\n");
        else printf("%lld\n",c[a+b-2][a-1]*f[n-1][a+b-2]%mod);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值