您的位置:首页 > 其它

排队 [HNOI 2012,Codevs 1994,Bzoj 2729]

2016-05-25 20:42 281 查看
题目的地址请点击——

排队

【题目描述】

某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。

他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻。

那么一共有多少种排法呢?(注意:任意两个人都是不同的)

【输入】

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

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

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

【输出】

仅包含一个非负整数,表示不同的排法个数。

注意答案可能很大。

【样例输入】

1 1

【样例输出】

12

【Solution】

这道题目我们可以分步进行计算。

注意到男生没有限制条件,而老师的个数也只有 2,所以我们可以先计算这两种人。

第一步,排男生。

因为一共有 n 个男生,所以有 n! 种排法。

第二步,排老师。

这个时候,就有两种情况了。

第一种,我们把两个老师在这一步就分开放。

将 2 个老师插入到已经排好的男生中。

因为有 n 个男生,所以一共有 n+1 个位置可以插入老师,排法有 P2n+1 种。

第二种,我们把两个老师排在一起。

把两个老师看成一个老师,这个新的老师有两种情况(因为两个老师可以顺序不同),然后再把这个新的老师插入到男生当中,排法有 2(n+1) 种。

第三步,排女同学。

对于老师的第一种排法,我们已经不需要考虑老师和男同学的区别了,因为老师的限制条件已经被解决了。

所以,我们要将 m 个女生插入 n+3 个空位中互相隔开,有 Pmn+3 种排法,

对于老师的第二种排法,我们需要将一个女生插入到两个老师之中,然后跟第一种情况一样的处理,有 m⋅Pm−1n+2 种排法。

综上所述,一共有 n!⋅P2n+1⋅Pmn+3+n!⋅2(n+1)⋅m⋅Pm−1n+2 种排法。

再加上高精度就可以 A 了。

Code

[cpp] #include <iostream>
#include <cstdio>
#include <cstring>

#define Max(x,y) ((x)>(y)?(x):(y))
#define LL long long
#define MOD 100000000

using namespace std;

struct bign{
int len;
LL s[1500];

bign(){
len=1;
memset(s,0,sizeof s);
s[1]=1;
}

bign operator = (const LL &num){
len=1;
s[1]=num;
return *this;
}

bign operator + (const bign&num){
bign c;c.s[1]=0;c.len=Max(num.len,len);
for(int i=1;i<=c.len;i++){
c.s[i+1]=(c.s[i]+s[i]+num.s[i])/MOD;
c.s[i]=(c.s[i]+s[i]+num.s[i])%MOD;
}
if(c.s[c.len+1])c.len++;
return c;
}

bign operator - (const bign&num){
bign c;c.s[1]=0;c.len=len;
int x=0;
for(int i=1;i<=c.len;i++){
c.s[i]=s[i]-num.s[i]+x;
x=0;
if(c.s[i]<0){
c.s[i]+=MOD;
x=-1;
}
}
while(!c.s[c.len]&&c.len>1)c.len–;
return c;
}

bign operator * (const LL&num){
bign c;c.s[1]=0;c.len=len;
for(int i=1;i<=c.len;i++){
c.s[i+1]=(c.s[i]+s[i]*num)/MOD;
c.s[i]=(c.s[i]+s[i]*num)%MOD;
}
if(c.s[c.len+1])c.len++;
return c;
}

bign operator * (const bign&num){
bign c;c.s[1]=0;c.len=len+num.len+1;
for(int i=1;i<=len;i++)
for(int j=1;j<=num.len;j++){
c.s[i+j]+=(c.s[i+j-1]+s[i]*num.s[j])/MOD;
c.s[i+j-1]=(c.s[i+j-1]+s[i]*num.s[j])%MOD;
}
while(!c.s[c.len]&&c.len>1)c.len–;
return c;
}

void out(){
for(int i=len;i>=1;i–){
if(i==len)printf(“%lld”,s[i]);
else printf(“%08lld”,s[i]);
}
}
};

LL n,m,tmp,tmp2;
bign ans1,ans2;

int main(){

scanf(”%lld%lld”,&n,&m);tmp=n+4;tmp2=n+3;
for(LL i=1;i<=n;i++){
ans1=ans1*i;
ans2=ans2*i;
}
ans1=ans1*(n+1)*n;
for(LL i=1;i<=m&&tmp>=0;i++){
tmp–;
ans1=ans1*tmp;
}
for(LL i=1;i<=m-1&&tmp2>=0;i++){
tmp2–;
ans2=ans2*tmp2;
}
ans2=ans2*2*m*(n+1);
(ans1+ans2).out();

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