#组合计数,第一类斯特林数#洛谷 4609 建筑师

题目

问有多少个 1 ∼ n 1\sim n 1n的排列,满足从左边只走上坡能看到 a a a个数,从右边只走上坡能看到 b b b个数


分析

那么先把最高值分开,那么左边有 a − 1 a-1 a1个,右边有 b − 1 b-1 b1个,那么共有 a + b − 2 a+b-2 a+b2个,而样子类似合唱队形还可以旋转,所以其实就是在 n − 1 n-1 n1个数中坐在 a + b − 2 a+b-2 a+b2个圆桌的方案数,再选择 a + b − 2 a+b-2 a+b2个数中选择 a − 1 a-1 a1个放左边,那么总而言之,答案就是
C ( a + b − 2 , a − 1 ) ∗ S t i r l i n g ( n − 1 , a + b − 2 ) C(a+b-2,a-1)*Stirling(n-1,a+b-2) C(a+b2,a1)Stirling(n1,a+b2),后面是第一类斯特林数,时间复杂度 O ( n a + T ) O(na+T) O(na+T)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=50001,M=201,mod=1e9+7;
int stir[N][M],c[M][M];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
	stir[0][0]=c[0][0]=1;
	for (rr int i=1;i<N;++i)
	for (rr int j=1;j<=i&&j<M;++j)
	stir[i][j]=mo(stir[i-1][j-1],1ll*(i-1)*stir[i-1][j]%mod);
	for (rr int i=1;i<M;++i){
	    c[i][0]=1;
		for (rr int j=1;j<=i;++j)
		    c[i][j]=mo(c[i-1][j],c[i-1][j-1]);
    }
	for (rr int t=iut();t;--t){
		rr int n=iut(),a=iut(),b=iut();
		print(1ll*stir[n-1][a+b-2]*c[a+b-2][a-1]%mod),putchar(10);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值