您的位置:首页 > 其它

排队[HNOI2012][Codevs1994]

2016-06-01 10:37 260 查看

题目描述 Description

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

样例输入 1

1 1

样例输入 2

7 3

样例输出 Sample Output

样例输出 1

12

样例输出 2

220631040

数据范围及提示 Data Size & Hint

对于 30% 的数据 n≤100,m≤100

对于 100% 的数据 n≤2000,m≤2000

分析

首先讨论特殊情况。

当 n=0 时,若 m=1 则 ans=2 。若 m=2 则 ans=8。否则 ans=0 。

当 m>n+3 时 ans=0 (必定会有两个女生相邻)

一般情况。

我们把 n 个同学和 1 个老师站成一列,这样有 (n+1)! 种可能的情况,再讨论另一个老师站的地方。

1 :两个老师不站在一起,此时这个老师共有 n 个可能的位置。剩下的 m 个女生将会站在每两个同学(老师)中间的位置或队头,队尾共 n+3 个位置,根据排列我们知道共有 Amn+3 种可能,根据乘法原理我们知道两个老师不站在一起的合法方案数共 n∗Amn+3 种可能

2 :两个老师站在一起,这两个老师的位置共有 2 个可能(老师的前后顺序有两种可能),此时两个老师之间必定站着一个女生,共 m 种可能,剩下的 m−1 个女生将会站在每两个同学(老师)中间的位置或队头,队尾共 n+2 个位置,根据排列我们知道共有 Am−1n+2 种可能,根据乘法原理我们知道两个老师站在一起的合法方案数共 2∗m∗Am−1n+2 种可能

综上,所有的可能情况有 (n+1)!∗(n∗Amn+3+2∗m∗Am−1n+2) 种。因为数据大,所以要打高精度

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;

const LL Mod = 100000000LL;

struct bignum{

LL a[4000];
int len;

bignum(int num=0){
memset(a,0,sizeof a);
a[0] = num;
len = 1;
}

bignum operator = (const bignum&h){
memcpy(a,h.a,sizeof h.a);
len = h.len;
return *this;
}

bignum operator = (const int h){
memset(a,0,sizeof a);
a[0] = h;
len = 1;
return *this;
}

bignum operator * (const int h){
bignum c;
for(int i=0;i<len;++i)
c.a[i] = a[i]*h;
for(int i=0;i<len;++i){
c.a[i+1] += c.a[i]/Mod;
c.a[i] %= Mod;
}
if(c.a[len])
c.len = len+1;
else
c.len = len;
return c;
}

bignum operator * (const bignum h){
bignum c;
c.len = len+h.len;
for(int i=0;i<len;++i)
for(int j=0;j<h.len;++j)
c.a[i+j] += a[i]*h.a[j];
for(int i=0;i<c.len;++i){
c.a[i+1] += c.a[i]/Mod;
c.a[i] %= Mod;
}
if(!c.a[c.len-1])
--c.len;
return c;
}

bignum operator + (const bignum h){
bignum c;
c.len = max(len,h.len);
for(int i=0;i<c.len;++i){
c.a[i] += a[i]+h.a[i];
c.a[i+1] += c.a[i]/Mod;
c.a[i] %= Mod;
}
if(c.a[c.len])
++c.len;
return c;
}

void display(){
printf("%lld",a[len-1]);
for(int i=len-2;i>=0;--i)
printf("%08lld",a[i]);
}

}ans(1);

int n,m;

int main(){

scanf("%d%d",&n,&m);

if(!n){
if(m == 1){printf("2");return 0;}
else if(m == 2){printf("8");return 0;}
else {printf("0");return 0;}
}
if(m > n+3){printf("0");return 0;}

for(int i=2;i<=n+1;++i)
ans = ans*i;

bignum tmp1(n);
for(int i=1;i<=m;++i)
tmp1 = tmp1*(n+4-i);

if(!m){
ans = ans*tmp1;
ans.display();
return 0;
}

bignum tmp2(2*m);
for(int i=1;i<=m-1;++i)
tmp2 = tmp2*(n+3-i);

ans = ans*(tmp1+tmp2);
ans.display();

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学