P3223 [HNOI2012]排队

题目描述

某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,

两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)

输入格式

只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。

输出格式

仅一个非负整数,表示不同的排法个数。注意答案可能很大。

输入输出样例

输入 #1

1 1

输出 #1

12

说明/提示

对于 30% 的数据 \(n\leq 100\)

对于 100% 的数据 \(n\leq 2000\)

这道题的柿子好难啊(蒟蒻我只能爬

首先,我们分两种情况讨论

  1. 当两个老师之间是男生的时候。 这还是很简单的

    首先先将\(n\)个男生排好队就是 \(A_{n}^{n}\)

    此时产生了\(n+1\)个空,把两位老师插进去就有\(A_{n+1}^{2}\)种方案

    然后就会产生\(n+3\)个空 再把\(m\)个女生放进去就会有\(A_{n+3}^{m}\)种方案

    那么综上第一种情况会有\(A_{n}^{n} \times A_{n+1}^{2} \times A_{n+3}^{m}\)

  2. 当由女生把老师隔开的时候,这种情况比较复杂,需要我们大力讨论

    首先,因为这个不管男生什么事,那我们就可以先把男生先排好也就是\(A_{n}^{n}\)

    然后,因为老师之间要是女生,所以我们可以把两个老师和一个女生当成一个整体,

    插入到\(n+1\)个空中,因为老师之间又是不同的,所以可以产生\(A_{2}^{2}\)种不同的排法

    再加上从\(m\)个女生中选出一个的方案数为\(C_{m}^{1}\),就会有\(A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1}\)

    至于剩下的\(m-1\)个女生直接插在\(n+2\)个空中就可以了,也就会产生\(A_{n+2}^{m-1}\)种方案

    综上第二种情况的方案数就为\(A_{n}^{n} \times A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1} \times A_{n+2}^{m-1}\)

最后的答案就是\(A_{n}^{n} \times A_{n+1}^{2} \times A_{n+3}^{m} + A_{n}^{n} \times A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1} \times A_{n+2}^{m-1}\)

这个柿子其实还是可以化简的,但是我忘了怎么化了(大雾

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,m,len = 1;
long long ans[11000];
long long p = 100000000;
void mul(int x){
	long long res = 0,num;
	for(int i = 1; i <= len; i++){
		num = ans[i] * x;
		ans[i] = num % p + res;
		res = num / p;//进位 
	}
	if(res != 0){
		len++;
		ans[len] = res;
	}
}
int main(){
	scanf("%lld%lld",&n,&m);
	ans[1] = 1;
	mul(n+1);
	mul(n*n+3*n+2*m);
	for(int i = 1; i <= n; i++){//计算n的阶乘 
		mul(i);
	}
	for(int i = n-m+4; i <= n+2; i++){//计算n+2的阶乘除以n-m+3的阶乘 
		mul(i);
	}
	cout<<ans[len];
	while(--len){
		printf("%08lld",ans[len]);
	}
	return 0;
}
//拜托不要卡cincout 远古时期的代码

posted @ 2020-08-13 18:34  genshy  阅读(139)  评论(0编辑  收藏  举报