题目描述
某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,
两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)
输入格式
只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。
输出格式
仅一个非负整数,表示不同的排法个数。注意答案可能很大。
输入输出样例
输入 #1
1 1
输出 #1
12
说明/提示
对于 30% 的数据 \(n\leq 100\)
对于 100% 的数据 \(n\leq 2000\)
这道题的柿子好难啊(蒟蒻我只能爬)
首先,我们分两种情况讨论
-
当两个老师之间是男生的时候。 这还是很简单的
首先先将\(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}\)
-
当由女生把老师隔开的时候,这种情况比较复杂,需要我们大力讨论
首先,因为这个不管男生什么事,那我们就可以先把男生先排好也就是\(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 远古时期的代码