【LG4609】[FJOI2016]建筑师

【LG4609】[FJOI2016]建筑师

题面

洛谷

题解

(图片来源于网络)

我们将每个柱子和他右边的省略号看作一个集合

则图中共有\(a+b-2\)个集合

而原来的元素中有\(n-1\)个(除去最后一个)

考虑第一类斯特林数的意义:

\(n\)个元素选出\(m\)个有序圆圈的方案数

我们将圆圈从中间最大处剪开则可以满足要求

则我们有\(s(n-1,a+b-2)\)种选法

因为要保证从左看有\(a\)

所以要乘上\(C(a+b-2,a-1)\)

\[\therefore Ans=C(a+b-2,a-1)\centerdot s(n-1,a+b-2) \]

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

inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
    if (ch == '-') w = -1 , ch = getchar();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    return w * data;
}
#define M 1000000007
#define MAX_N 50005
#define MAX_A 105
int N, A, B;
int C[MAX_A * 2][MAX_A * 2], S[MAX_N][MAX_A * 2];

int main () {
	for (int i = 0; i <= 200; i++) S[i][i] = 1;
	for (int i = 2; i < 50000; i++)
		for (int j = 1; j <= min(i, 200); j++)
			S[i][j] = (1ll * (i - 1) * S[i - 1][j] % M + S[i - 1][j - 1]) % M;
	for (int i = 0; i <= 200; i++) C[i][i] = C[i][0] = 1;
	for (int i = 1; i <= 200; i++)
		for (int j = 1; j < i; j++)
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % M;
	int T = gi();
	while (T--) {
		N = gi(), A = gi(), B = gi();
		printf("%d\n", 1ll * S[N - 1][A + B - 2] * C[A + B - 2][A - 1] % M); 
	}
	return 0; 
}
posted @ 2019-01-16 19:36  heyujun  阅读(387)  评论(0编辑  收藏  举报