BZOJ 2729 [HNOI2012]排队

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2729

题目大意: n 名男同学,名女同学和两名老师排队,并且任意两名女同学不能相邻,两名老师也不能相邻,求方案数。

分析:赤果果的排列组合嘛,不会就去问数学老师吧。

盗图一张:

不过还要加高精度。有一个小优化就是把因子存在一个数组里,能约掉的约掉后再高精度乘起来。但是数据很小所以没太大的必要,所以直接高精了。

 

附代码:

View Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
#define MaxL 2000
const long long MOD=1000000000;
struct Bignum
{
    int len;
    long long a[MaxL];
    void init()
    {

        }
    Bignum()
    {
        len=0;
        memset(a,0,sizeof(a));
        }
};

int n,m;
Bignum ans1,ans2;

void operator *= (Bignum &p,int x)
{
    int tmp=0;
    for (int i=1;i<=p.len;++i)
    {
        p.a[i]=p.a[i]*x+tmp;
        tmp=p.a[i]/MOD;
        p.a[i]%=MOD;
        }
    if (tmp)
    p.a[++p.len]=tmp;
    }

Bignum operator + (Bignum x,Bignum y)
{
    int len=max(x.len,y.len);
    int tmp=0;
    for (int i=1;i<=len;++i)
    {
        x.a[i]=x.a[i]+y.a[i]+tmp;
        tmp=x.a[i]/MOD;
        x.a[i]%=MOD;
        }
    x.len=len;
    if (tmp)
        x.a[++x.len]=tmp;
    return x;
    }

Bignum operator * (Bignum x,Bignum y)
{
    Bignum p;
    p.len=0;
    for (int i=1;i<MaxL;++i)
        p.a[i]=0;
    for (int i=1;i<=x.len;++i)
    {
        int tmp=0;
        for (int j=1;j<=y.len;++j)
        {
            p.a[i+j-1]=p.a[i+j-1]+x.a[i]*y.a[j]+tmp;
            tmp=p.a[i+j-1]/MOD;
            p.a[i+j-1]%=MOD;    
            }
        if (tmp)
        p.a[i+y.len]+=tmp;
    }
    int tmp=0;
    for (int i=1;i<MaxL;++i)
    {
        p.a[i]=p.a[i]+tmp;
        tmp=p.a[i]/MOD;
        p.a[i]%=MOD;
        }
    for (int i=MaxL-1;i>=1;--i)
    if (p.a[i])
    {
        p.len=i;
        break;
        }
    if (!p.len) p.len=1;
    return p;
    }

void write(Bignum p)
{
    
    printf("%lld",p.a[p.len]);
    for (int i=p.len-1;i>=1;--i)
    printf("%09lld",p.a[i]);
    printf("\n");
    }

Bignum A(int n,int m)
{
    Bignum p;
    p.len=1;
    p.a[1]=1;
    for (int i=0;i<m;++i)
        p*=(n-i);
    return p;
    }

int main()
{
    scanf("%d%d",&n,&m);
    if (n>=1 && n+3>=m)
    {
        ans1=A(n+3,m);
        ans1*=((n+1)*n);
        }
    if (m>=1 && n+3>=m)
    {
        ans2=A(n+2,m-1);
        ans2*=(2*(n+1)*m);
        }
    write(A(n,n)*(ans1+ans2));
    return 0;
    }

 

 

写这个题是现学的高精乘高精啊...

posted @ 2012-05-04 15:45  Evan1004  阅读(581)  评论(0编辑  收藏  举报