HDU4372:Count the Buildings

18 篇文章 0 订阅
7 篇文章 0 订阅

HDU4372:Count the Buildings

题目大意

传送门
在这里插入图片描述

思路

个人觉得这位巨佬的博客讲的异常之好。我们把所有建筑物中最高的那个玩意提出来(塔的高度是1~n),我们知道无论从哪边看,这个最高的塔一定能够被看到,所以,我们就以这座塔为分界线。我们考虑,左边需要有 F − 1 F-1 F1幢,我们想一下能看到它们的条件,就是这 F − 1 F-1 F1幢是单调上升的,以此类推,右边 B − 1 B-1 B1幢能看到的条件就是从左往右单调递减。我们对于左边能够看到的 F − 1 F-1 F1幢,我们设 a i a_i ai为第i幢能看到的塔的编号,那么我们就可以把 a i a_i ai ~ a i + 1 − 1 a_{i+1}-1 ai+11分为一个区间,因为这个区间只有一个能够被看到,那我们想到了什么呢?什么都没有这不可以用第一类斯特林数么?因为第一类斯特林数是求的把n个点构成m个圆,而这道题一个区间跟圆的性质是相似的,因为这正好就是非空循环排列,第一类斯特林数中提到的名词,每一个不同排列的环,都可以形成唯一一个以最大元素为开头的排列,即把该环从最大元素处打开。 (出自Nature_Ran的博客)所以除了中间最高的塔,其他 n − 1 n-1 n1个点可以分为 F − 1 + B − 1 F-1+B-1 F1+B1组,然后我们就从这 F − 1 + B − 1 F-1+B-1 F1+B1组中选出 F − 1 F-1 F1组放左边,所以就是 s [ N − 1 ] [ F + B − 2 ] × C ( F + B − 2 , F − 1 ) s[N-1][F+B-2]\times C(F+B-2,F-1) s[N1][F+B2]×C(F+B2,F1)(就是上一句话的数学表示)

代码

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm> 
using namespace std;

#define Int register int
#define int long long
#define mod 1000000007
#define MAXN 2005

int N,F,B;
int s[MAXN][MAXN],c[MAXN][MAXN];
int inv[MAXN],inv_fac[MAXN],fac[MAXN];

void init()
{
	s[0][0] = 1;
	c[0][0] = 1;
	for (Int i = 1;i <= 2000;++ i)
	{
		c[i][0] = c[i][i] = 1;
		s[i][0] = 0;s[i][i] = 1;
		for (Int j = 1;j < i;++ j)	
		{
			c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
			s[i][j] = (s[i - 1][j - 1] % mod + s[i - 1][j] % mod * (i - 1) % mod) % mod;
		}
	}

}

int C (int n,int m)
{
	return c[n][m];
}

void read (int &x)
{
	x = 0;char c = getchar();int f = 1;
	while(c < '0' || c > '9'){if(c == '-')f = -f;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - '0';c = getchar();}
	x *= f;return ;
}

void write (int x)
{
	if (x < 0){x = -x;putchar('-');}
	if (x > 9) write (x / 10);
	putchar (x % 10 + '0');
}

signed main()
{
	init();
	int times;
	read (times);
	while (times --)
	{
		read (N),read (F),read (B);
		if (F + B - 2 > N) puts ("0");
		else write (s[N - 1][F + B - 2] % mod * c[F + B - 2][F - 1] % mod),putchar ('\n');
	}
	return 0;
}
//s(n,m)=s(n-1,m-1)+s(n-1,m)*(n-1)
//s(n-1,F+B-2)*C(F+B-2,F-1)
//3 2 2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值