您的位置:首页 > 其它

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

2017-04-14 20:14 316 查看
点击这里查看原题

组合数问题,需要用到高精度。

把男生和老师混在一起,中间插入女生。两个老师刚好连在一起的情况为

A ( n+1 , n+1 ) * A ( 2 , 2 )

这种情况下两个老师间必须插入女生,于是将两个老师和一个女生捆绑在一起,情况为

m * A ( n+1 , n+1 ) * A ( 2 , 2 )

然后将剩余女生插入,情况为

A ( n+2 , m-1 )

两个老师不连在一起的情况为

A ( n+2 , n+2 ) - A ( n+1 , n+1 ) * A ( 2 , 2 )

直接插入女生的情况为

A ( n+3 , m )

于是,最终答案为

m * A ( n+1 , n+1 ) * A ( 2 , 2 ) * A ( n+2 , m-1 ) + A ( n+2 , n+2 ) - A ( n+1 , n+1 ) * A ( 2 , 2 ) * A ( n+3 , m )

高精度数组不能开太大,我最初开了5e4一直TLE。

/*
User:Small
Language:C++
Problem No.:2729
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
int n,m;
struct bignum{
int len,c[10005];
bignum(){
len=0;
memset(c,0,sizeof(c));
}
}x,y,z;
bignum operator+(const bignum a,const bignum b){
bignum c;
c.len=max(a.len,b.len);
for(int i=1;i<=c.len;i++){
c.c[i]+=b.c[i]+a.c[i];
if(c.c[i]>=10000){
c.c[i+1]++;
c.c[i]-=10000;
}
}
if(c.c[c.len+1]) c.len++;
return c;
}
bignum operator-(const bignum a,const bignum b){
bignum c;
c.len=a.len;
for(int i=1;i<=c.len;i++){
c.c[i]+=a.c[i]-b.c[i];
if(c.c[i]<0){
c.c[i+1]--;
c.c[i]+=10000;
}
}
while(c.c[c.len]==0) c.len--;
return c;
}
bignum mul(bignum a,int b){
bignum c;
if(b==0){
for(int i=1;i<=c.len;i++) c.c[i]=0;
c.len=1;
return c;
}
c.len=a.len;
for(int i=1;i<=c.len;i++){
c.c[i]+=b*a.c[i];
c.c[i+1]+=c.c[i]/10000;
c.c[i]%=10000;
}
while(c.c[c.len+1]) c.len++;
return c;
}
void write(bignum p){
printf("%d",p.c[p.len]);
for(int i=p.len-1;i;i--) printf("%04d",p.c[i]);
printf("\n");
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d",&n,&m);
if(n+m==0||m>n+3){
printf("0\n");
return 0;
}
x.len=1;
x.c[1]=1;
y=z=x;
x=mul(x,m);
for(int i=2;i<=n+1;i++) x=mul(x,i);
x=mul(x,2);
for(int i=n+4-m;i<=n+2;i++) x=mul(x,i);
for(int i=2;i<=n+2;i++) y=mul(y,i);
for(int i=2;i<=n+1;i++) z=mul(z,i);
z=mul(z,2);
y=y-z;
for(int i=n+4-m;i<=n+3;i++) y=mul(y,i);
x=x+y;
write(x);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: