[HDU]4372 Count the Buildings 第一类斯特林数

Count the Buildings

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


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

  专爆RE差评...

  这道题大意就是说一个n高度不同的房屋, 从左边看能看到f个, 从右边看能看到b个. 问方案数.

  实际上就是楼房就是排列... 那么从左往右和从右往左显然最后能看到的就是那个最高的房屋. 于是我们考虑那个最高的. 那么最高的左边有f - 1个可见房屋, 右边有b - 1个可见房屋. 那么我们把一个可见房屋到下一个可见房屋之前分为一段. 则最高的房屋左边就有f - 1段, 右边有b - 1段. 我们先考虑左边的f - 1段. 对于左边每一段, 因为由我们分段的方式, 这一段最高的房屋一定在这一段的左端——那么也就是说本段其他的元素可以随便排列. 那么实际上我们会发现每段就是一个圆排列. 右边的跟左边同样的分析方法. 那么我们现在相当于在除了最高的房屋, 剩下的n - 1个不同元素(房屋) 选出(f - 1) + (b - 1)个圆排列(段)来, 并选择f - 1个放在左边, 剩下的放在右边. 显然把f - 1个放在左边不用再讨论这f - 1段(圆排列)的先后次序, 因为题目中要求高度递增(从左到右), 那么选择了f - 1段后放在左边的方式就固定了. 右边同理. 那么对于n - 1个元素里选出f + b- 2个圆排列来——这显然就是第一类斯特林数的定义. 而后面的选择直接上组合数就可以了.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005;
const int mod = 1e9 + 7;
int T, n, x, y;
long long c[maxn][maxn], s[maxn][maxn];
void init() {
	for (int i = 0; i < maxn; ++ i) {
		c[i][0] = 1;
		s[i][0] = (!i) ? 1 : 0;
		for (int j = 1; j <= i; ++ j) {
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod; 
			s[i][j] = (s[i - 1][j - 1] + (i - 1) * s[i - 1][j] % mod) % mod;
		}
	}
}
int main() {
	init();
	scanf("%d", &T);
	while (T --) {
		scanf("%d%d%d", &n, &x, &y);
		if (x + y - 2 > 2000) puts("0");
		else printf("%lld\n", s[n - 1][x + y - 2] * c[x + y - 2][x - 1] % mod);
	}
}


  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值