Description
某中学有n名男同学,m名女同学和两名老师要排队参加体检。他们排成一条直线,并且
任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意任意两个人都是不同的)
Input
输入只有一行且为用空格隔开的两个非负整数n和m,其含义如上所述。
Output
仅包含一个非负整数,表示不同的排法个数.
Sample Input
【输入样例 1】
1 1
【输入样例 2】
7 3
Sample Output
【输出样例 1】
12
【输出样例 2】
220631040
Data Constraint
Hint
对于30%, n<=100,m<=100
对于100%, n<=2000,m<=2000
The Solution
这道题目,我们可以先分类讨论。
如果
n+3<m
则显然无解,输出0,
如果
n+3>=m
则进行分析:
我们可以先处理男生和老师。
① 排男生。因为一共有 n 个男生,所以有 n! 种排法。
② 排老师。
这个时候,就有两种情况了。
第一种,我们把两个老师在这一步就分开放。
将 2 个老师插入到已经排好的男生中。
因为有 n 个男生,所以一共有 n+1 个位置可以插入老师,排列的方法有
第二种,我们把两个老师排在一起。
把两个老师看成一个老师,这个新的老师有两种情况(因为两个老师可以顺序不同),然后再把这个新的老师插入到男生当中,排列的方法有 2(n+1) 种。
③排女同学。
对于老师的第一种排法,我们已经不需要考虑老师和男同学的区别了,因为老师的限制条件已经被解决了。
所以,我们要将 m 个女生插入 n+1+2=n+3 个空位中互相隔开,
有
对于老师的第二种排法,
我们需要将一个女生插入到两个老师之中(即:(老师,女生,老师),然后跟第一种情况一样的处理,
有
综上所述,
一共有:
提取公因式得:
最后高精度即可,可以压位。
PS.排列的计算为:
CODE
#include <cstdio>
#include <iostream>
#include <cstring>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define fd(i,a,b) for (int i=a;i>=b;i--)
#define N 2005
#define ya 100000000
using namespace std;
struct note
{
int len;
long long num[N];
}a;
int n,m;
note gjc(note a,int x)
{
note c;
memset(c.num,0,sizeof(c.num));
c.len=a.len;
fo(i,1,c.len)
{
c.num[i]+=a.num[i]*x;
c.num[i+1]+=c.num[i]/ya;
c.num[i]=c.num[i]%ya;
}
while (c.num[c.len+1]) c.len++;
return c;
}
int main()
{
scanf("%d%d",&n,&m);
if (n+3<m) {printf("0\n"); return 0;}
int k=n*(n+3)+m*2;
a.len=1;
a.num[1]=k;
fo(i,1,n+1) a=gjc(a,i);
fo(i,n-m+4,n+2) a=gjc(a,i);
printf("%d",a.num[a.len]);
fd(i,a.len-1,1) printf("%08d",a.num[i]);
return 0;
}