排队[HNOI2012][Codevs1994]

原创 2016年06月01日 10:37:33

题目描述 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;

}
版权声明:本文为博主原创文章,未经博主允许不得转载。

[BZOJ2729][HNOI2012]排队(组合数学+高精度)

立足和发展中国特色社会主义实践。。
  • FromATP
  • FromATP
  • 2017年06月15日 08:16
  • 178

【BZOJ2729】【HNOI2012】排队 组合数 数论 Python高精度

题解: 代码里面有注释。 注意: Python2中的中文字符即使注释了,也会CE(当然,因为Python是直接运行,不编译,所以显示WA) 呃,而本地的Python3就不管它了。。 所以我的代码需...
  • Vmurder
  • Vmurder
  • 2015年01月21日 09:58
  • 1687

【HNOI2012】【BZOJ2729】排队

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

[BZOJ 2729][HNOI2012]排队:高精度+组合数

点击这里查看原题组合数问题,需要用到高精度。 把男生和老师混在一起,中间插入女生。两个老师刚好连在一起的情况为 A ( n+1 , n+1 ) * A ( 2 , 2 ) 这种情况下两个老师...

20160318 CodeVS 1215 走迷宫,3286 火柴排队,2618 核电站问题

CodeVS 1215 走迷宫,3286 火柴排队,2618 核电站问题

【codevs 3286】火柴排队

**题目描述 Description** 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为: ,其中 ...
  • fd_xuan
  • fd_xuan
  • 2015年10月13日 14:09
  • 280

Codevs3286 火柴排队

题目大意:给定两个长度为n的序列,序列中相邻的数可以相互交换。求至少交换多少次才能使火柴之间的距离和最小。 思路:可以用排序不等式证明,当每一根火柴与在各自排完序的序列中的序号相同者配对时,才有最小距...

【基础练习】【离散化+逆序对】codevs3286 火柴排队题解

题目来自2013NOIPTG 题目描述 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同...
  • ametake
  • ametake
  • 2015年10月25日 09:12
  • 543

CJOJ 1308 【HNOI 2002 】营业额统计 / CodeVS 1296 营业额统计

CJOJ 1308 【HNOI 2002 】营业额统计 / CodeVS 1296 营业额统计

有趣的数列[HNOI2009][Codevs2337]

题目描述 Description我们称一个长度为 2n 2n 的数列是有趣的,当且仅当该数列满足以下三个条件: ( 1 1 ) 它是从 1 1 到 2n 2n 共 2n 2n 个整数的一...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:排队[HNOI2012][Codevs1994]
举报原因:
原因补充:

(最多只允许输入30个字)