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

3 篇文章 0 订阅
1 篇文章 0 订阅

点击这里查看原题

组合数问题,需要用到高精度。
把男生和老师混在一起,中间插入女生。两个老师刚好连在一起的情况为
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值