关闭

排队[HNOI2012][Codevs1994]

标签: 数学
185人阅读 评论(0) 收藏 举报
分类:

题目描述 Description

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


输入描述 Input Description

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


输出描述 Output Description

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


样例输入 Sample Input

样例输入 1

1 1

样例输入 2

7 3


样例输出 Sample Output

样例输出 1

12

样例输出 2

220631040


数据范围及提示 Data Size & Hint

对于 30% 的数据 n100,m100
对于 100% 的数据 n2000,m2000


分析

首先讨论特殊情况。
n=0 时,若 m=1ans=2 。若 m=2ans=8。否则 ans=0
m>n+3ans=0 (必定会有两个女生相邻)

一般情况。
我们把 n 个同学和 1 个老师站成一列,这样有 (n+1)! 种可能的情况,再讨论另一个老师站的地方。
1 :两个老师不站在一起,此时这个老师共有 n 个可能的位置。剩下的 m 个女生将会站在每两个同学(老师)中间的位置或队头,队尾共 n+3 个位置,根据排列我们知道共有 Amn+3 种可能,根据乘法原理我们知道两个老师不站在一起的合法方案数共 nAmn+3 种可能
2 :两个老师站在一起,这两个老师的位置共有 2 个可能(老师的前后顺序有两种可能),此时两个老师之间必定站着一个女生,共 m 种可能,剩下的 m1 个女生将会站在每两个同学(老师)中间的位置或队头,队尾共 n+2 个位置,根据排列我们知道共有 Am1n+2 种可能,根据乘法原理我们知道两个老师站在一起的合法方案数共 2mAm1n+2 种可能
综上,所有的可能情况有 (n+1)!(nAmn+3+2mAm1n+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;

}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:31978次
    • 积分:1554
    • 等级:
    • 排名:千里之外
    • 原创:128篇
    • 转载:0篇
    • 译文:0篇
    • 评论:5条
    最新评论