HDU - 4372 Count the Buildings 【stirling数】

Count the Buildings

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3026    Accepted Submission(s): 1000


 

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 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

 

 

Source

2012 Multi-University Training Contest 8

 

 

Recommend

zhuyuanchen520

 

 

题意:N个房子,高度为1到N。从左边看能看到F个,右边能看到B个,求满足此条件的方案数。

分析:最高的房子两边一定都能看到,那么左边剩F-1个,这F-1个一定是升序排列,右边剩B-1个,降序排列,总共为F+B-2个,

可以将剩下的N-1个数分为F+B-2个组,其中每组的高度为该组中最高的,剩余的排列在这个右边(从左边看)或左面(从右边看),通过stirling数来解决。

第一类Stirling数表示将 n 个不同元素构成m个圆排列的数目。

递推式满足s(n,m)=s(n-1,m-1)+(n-1)*s(n-1,m)

最后ans=s(n-1,f+b-2)*C_{f+b-2}^{f-1}

代码乱写,重要的是思路

//#include <bits/stdc++.h>
#include "cstdio"
#include "cstring"
#include "iostream"
using namespace std;
const int mod = 1e9+7;
long long inv[2004];
long long fac[2004];
long long s[2004][2004];
long long qk(long long a,long long n)
{
    long long ans=1;
    while(n)
    {
        if(n&1)ans=a*ans%mod;
        n>>=1;
        a=a*a%mod;
    }
    return ans;
}
long long c(long long a,long long b)
{
    if(a==b)return 1;
    if(a<b)return 0;
    return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
long long dfs(long long n,long long m)
{
    if(n<m)return 0;
    if(n==m)return 1;
    if(m==0)return 0;
    if(s[n][m]!=0)return s[n][m];
    else {
        s[n][m]=(dfs(n-1,m-1)+(n-1)*dfs((n-1),m)%mod)%mod;
        return s[n][m];
    }
}
void init()
{
    memset(s,0, sizeof(s));
    s[1][1]=1;
    fac[0]=fac[1]=1;
    for(int i=2;i<=2000;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[2000]=qk(fac[2000],mod-2);
    for(int i=2000-1;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}
int main () {
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,f,b;
        cin>>n>>f>>b;
        printf("%lld\n",dfs(n-1,f+b-2)*c(f+b-2,f-1)%mod);
    }

}

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值