zoukankan      html  css  js  c++  java
  • 排列组合,高精度

    A. 排队

    内存限制:128 MiB 时间限制:1000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较
     

    题目描述

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

    输入格式

    只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。
    对于 30%的数据 n≤100,m≤100
    对于 100%的数据 n≤2000,m≤2000

    输出格式

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

    样例

    样例输入

    1 1   
    

    样例输出

     12
    

    析:经过数奥大佬MXD的开导,想到了本题一种较清晰的思路。
    老师之前要么是男生,要么是女生,所以分两种情况:
    1.老师之间是男生,所以组合共有 A(n,n)*A(n+1,2)*A(n+3,m)
    2.老师之间是女生,则将两个老和一个女生看成一个人,则组合有 A(n,n)*A(n+1,1)*A(n+2,m-1)*A(2,2)*C(m,1)
    将结果相加即可

    注意,本题是高精度乘低精度,可以用更简单的方式计算
    而不用将每个数变成高精度,会超时!!
    void workk(int x,int f[],int l)
    {
        for(re i=1;i<=l;i++)
            f[i]*=x;
        for(re i=1;i<=l;i++)
        {
            if(f[i]>=10)
            {
                f[i+1]+=f[i]/10;
                f[i]%=10;
            }
        }
        while(f[l+1])
        {
            ++l;
            f[l+1]+=f[l]/10;
            f[l]%=10;
        }
        f[0]=l;
    }

    #include<bits/stdc++.h>
    #define N 1000010
    #define re register int
    using namespace std;
    int l1,l2,n,m;
    int a[N],b[N],c[N];
    void get_n()
    {
        for(re i=2; i<=n; i++)
        {
            for(re j=1; j<=l1; j++)
                a[j]=a[j]*i;
            for(re j=1; j<=l1; j++)
                if(a[j]>=10)
                {
                    a[j+1]+=a[j]/10;
                    a[j]=a[j]%10;
                }
            while(a[l1+1])
            {
                l1++;
                a[l1+1]+=a[l1]/10;
                a[l1]=a[l1]%10;
            }
        }
        a[0]=l1;
        for(re i=0;i<=a[0];i++)
            b[i]=a[i];
    }
    void workk(int x,int f[],int l)
    {
        for(re i=1;i<=l;i++)
            f[i]*=x;
        for(re i=1;i<=l;i++)
        {
            if(f[i]>=10)
            {
                f[i+1]+=f[i]/10;
                f[i]%=10;
            }
        }
        while(f[l+1])
        {
            ++l;
            f[l+1]+=f[l]/10;
            f[l]%=10;
        }
        f[0]=l;
    }

    void in1()//A(n,n)*A(n+1,2)*A(n+3,m);
    {
        workk(n,a,a[0]);
        workk(n+1,a,a[0]);
        
        for(re i=n+3;i>=n+3-m+1;i--)
            workk(i,a,a[0]);
        /*for(re i=a[0];i>0;i--)
            cout<<a[i];
        cout<<endl;*/
    }
    void in2()//A(n,n)*A(n+1,1)*A(n+2,m-1)*A(2,2)*m
    {
        workk(n+1,b,b[0]);
        workk(2,b,b[0]);
        workk(m,b,b[0]);
        for(re i=n+2;i>=n+2-m+2;i--)
            workk(i,b,b[0]);
    }
    void add()
    {
        c[0]=max(a[0],b[0]);
        for(re i=1;i<=c[0];i++)
            c[i]+=a[i]+b[i];
        for(re i=1;i<=c[0];i++)
            if(c[i]>=10)
            {
                c[i+1]+=c[i]/10;
                c[i]%=10;
            }
        while(c[c[0]])
            ++c[0];
        --c[0];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        if(n==0&&m==0)
        {
            printf("0\n");
            return 0;
        }
        a[1]=1;
        a[0]=1;
        l1=1;
        b[1]=1;
        a[0]=1;
        get_n();
        
        in1();
        //cout<<"YES"<<endl;
        in2();
        add();
        for(re i=c[0];i>0;i--)
            printf("%d",c[i]);
        return 0;
    }
  • 相关阅读:
    设计模式之-简单工厂模式
    C# 汉语转拼音
    深入理解DIP、IoC、DI以及IoC容器
    C# 各种帮助类大全
    C# TCP多线程服务器示例
    【AtCoder】AGC004
    【AtCoder】ARC061
    【AtCoder】CODE FESTIVAL 2016 qual A
    【AtCoder】AGC005
    【AtCoder】CODE FESTIVAL 2016 qual B
  • 原文地址:https://www.cnblogs.com/WindZR/p/14626037.html
Copyright © 2011-2022 走看看