[BZOJ2729]排队

数学知识


排列  A(n,m)从n个元素中选出m个的不同的排列数  A(n,m)=n!/(n-m)!

组合  C(n,m)从n个元素中选出m个的不同的方案数  C(n,m)=n!/(m!*(n-m)!)

 


 

题目传送门

题目描述

某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)

输入格式

只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。
对于 30%的数据 n≤100,m≤100
对于 100%的数据 n≤2000,m≤2000

输出格式

输出文件 output.txt 仅包含一个非负整数,表示不同的排法个数。注意答案可能很大。

样例

样例输入

1 1

样例输出

 12

 

题解

1.首先,很容易想到 

    所有男生全排列,然后老师和女生分别插空,即A(n,n)*A(n+1,2)*A(n+3,m)

2.但是手模样例,发现少情况了,细细一想,

     老师中间只有女生的情况没有考虑

    男生全排列,然后女生选一个,接着老师前后排,两个老师加一个女生捆绑后,在男生中插空,最后别忘了把剩下的m-1个女生插到n+1+1个空里

    即  A(n,n)*A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1)

所以根据分步加法原理

    两种情况相加,并化简

    得  n!*(n+2)!*(n+1)(n^2+3*n+2*m)/(n-m+3)!

    再用高精乘低精即可很容易实现

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 
 5 int n,m,len=1,a[100000001];
 6 
 7 void mul(int x)
 8 {
 9     int k=0;
10     for(int i=1;i<=len;i++)
11     {
12         a[i]=a[i]*x+k;
13         k=a[i]/10;
14         a[i]%=10;
15         if(k>0&&i==len)  len++;
16     }
17 }
18 signed main()
19 {
20     scanf("%d%d",&n,&m);
21     a[1]=1;len=1;
22     for(int i=1;i<=n+1;i++)
23         mul(i);
24     for(int i=n-m+4;i<=n+2;i++)
25         mul(i);    
26     mul(n*n+n*3+m*2);
27     for(int i=len;i>=1;i--)
28         printf("%d",a[i]);
29 }
View Code

 

posted @ 2019-07-06 12:21  casun547  阅读(174)  评论(0编辑  收藏  举报