zoukankan      html  css  js  c++  java
  • [bzoj2729][HNOI2012]排队 题解 (排列组合 高精)

    Description

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

    Input

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

    Output

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

    Sample Input

    1 1

    Sample Output

    12
     
     

    码题5分钟,推导两小时

    对于“不能相邻”,考虑采用插空法

    首先对于无限制的男生有$A_n^n$种排列

    这时产生了n+1个空档,插入2个老师还要$*A_{n+1}^2$

    现在有n+3个空档,放m个女生有$A_{n+3}^m$种

    此时的所有情况都满足条件

    但只考虑了男生隔开老师的情况

    而女生也可以隔开老师

    考虑捆绑play(雾)

    让两个老师一个女生卡在一起(卢老爷我错辽)

    这种组合放入男生队伍中有$n+1$种位置

    选着一个女生有m种

    放剩下的$A_{n+2}^{m-1}$

    老师排列方式$A_2^2=2$

    男生排列方式$A_n^n$

    $ANS=A_n^n*A_{n+1}^2*A_{n+3}^m+(n+1)*2*A_n^n*m*A_{n+2}^{m-1}$

    连高精乘低精都不会打了真是耻辱

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=100005;
    int n,m,num1[N],num2[N],tot[N];
    /*int intlen(int x)
    {
        return (int)log10(x)+1;
    }
    void turn(int x,int num[])
    {
        int l=0;
        while(x)
        {
            int now=x%10;
            num[++l]=now;
            x/=10;
        }
        num[0]=l;
        //reverse(num+1,num+l+1);
    }*/
    void mult(int x,int num[])
    {
        int k=0;
        for(int i=1;i<=num[0];i++)
        {
            int tmp=num[i]*x+k;
            num[i]=tmp%10;
            k=tmp/10;
        }
        while(k)num[++num[0]]=k%10,k/=10;
    }
    void sum(int a1[],int a2[],int res[])
    {
        int j=1,x=0;
        while(j<=a1[0]||j<=a2[0])
        {
            res[j]=a1[j]+a2[j]+x;
            x=res[j]/10;
            res[j]%=10;
            j++;
        }
        res[j]=x;
        if(!res[j])j--;
        res[0]=j;
    }
    void print(int a[])
    {
        for(int i=a[0];i;i--)printf("%d",a[i]);
        puts(" ");
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        //turn(n,num1);turn(m,num2);
        num1[0]=num1[1]=1;
        for(int i=1;i<=n;i++)mult(i,num1);
        for(int i=n+1;i>=n;i--)mult(i,num1);
        for(int i=n+3;i>=n-m+4;i--)mult(i,num1);
        num2[0]=num2[1]=1;
        mult(n+1,num2);
        mult(m,num2);
        mult(2,num2);
        for(int i=n+2;i>=n+2-(m-1)+1;i--)mult(i,num2);
        for(int i=1;i<=n;i++)mult(i,num2);
        //print(num1);print(num2);
        sum(num1,num2,tot);
        print(tot);
        return 0;
    }
    View Code
  • 相关阅读:
    Hibernate的实体类为什么要实现Serializable序列化接口?
    TextBox的SelectionChanged事件及TextBox的Select属性
    wpf的Expander的使用
    使用ScrollViewer实现按钮控制滚动
    popup的使用(一)
    winform中动态生成多行label,同时添加滚动条
    关于CheckListBox触发ItemCheck事件的问题
    protobuf3的学习笔记
    jQuery总结
    青春无悔
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11101993.html
Copyright © 2011-2022 走看看