其他分享
首页 > 其他分享> > [BZOJ2729]:[HNOI2012]排队

[BZOJ2729]:[HNOI2012]排队

作者:互联网

题目传送门


题目描述:

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


输入格式:

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


输出格式:

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


数据范围与提示:

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


题解:

一道组合数学的入门题,还不会组合数学的可以跳转这篇博客:组合数学入门

ppt上的例题,附带讲解:

但是呢?我懒。

这也太麻烦了吧?!

于是,自己推式子:

依然分类讨论:

先讨论两个老师中间只站一个女生,将老师和那个女生看为一个整体:

A(m,1)×A(n,n)×A(n+1,1)×A(2,2)×A(n+2,m-1)。

接着讨论两个男生中间站一个老师的情况:

A(n,n)×A(n+1,2)×A(n+3,m)。

然后整理化简得:(n2+3×n+2×m)×(n+1)!×(n-m+4)×(n-m+5)×…×(n+2)。


代码时刻:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int l=1;
long long ans[100001],flag1,flag2;
void wzc(int x)//高精乘低精
{
    flag2=0;
    for(int i=1;i<=l;i++)
    {
        flag1=ans[i]*x;
        ans[i]=flag1%1000000000000000+flag2;
        flag2=flag1/1000000000000000;
    }
    if(flag2)ans[++l]=flag2;
}
int main()
{
    ans[1]=1;
    scanf("%d%d",&n,&m);
    wzc(n*n+n*3+2*m);
    for(int i=1;i<=n+1;i++)
        wzc(i);
    for(int i=n-m+4;i<=n+2;i++)
        wzc(i);
    cout<<ans[l];
    while(--l)
    {
	    cout.fill('0');//不足补0
		cout<<setw(15)<<ans[l];
	}
    return 0;
}

rp++

标签:排法,int,BZOJ2729,排队,long,HNOI2012,flag2,老师,100
来源: https://www.cnblogs.com/wzc521/p/11102906.html