【LG4609】[FJOI2016]建筑师

【LG4609】[FJOI2016]建筑师

题面

洛谷

题解

(图片来源于网络)

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

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

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

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

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

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

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

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

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

[ herefore 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
", 1ll * S[N - 1][A + B - 2] * C[A + B - 2][A - 1] % M); 
	}
	return 0; 
}
原文地址:https://www.cnblogs.com/heyujun/p/10278955.html