zoukankan      html  css  js  c++  java
  • bzoj2729: [HNOI2012]排队

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2729

    思路:简单的排列组合题

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

    首先我们观察,男生无限制,先把男生排好即A(n,n)

    然后我们排老师,老师不能相邻,n个男生有n+1个空位

    如果老师被男生隔开,即有A(n+1,2)的方案

    现在有了n+3个空位,还要放m个女生

    即A(n+3,m)这就是式子加号前的部分


    但是,在排女生前,老师可以相邻,只要我们后面用一个女生隔开

    这样我们就有A(n,n)*A(2,2)*A(m,1)*A(n+2,m-1)种方案

    即枚举两个老师的顺序,枚举中间的女生,最后有n+2个位置(两个老师捆在一起了)放剩下的m-1个女生


    如果我们先排女生,再排老师,我们就会有很多种情况讨论

    因为排完男生后,可以有两个女生相邻,可以有两组,每组两个女生相邻,还可以有三个女生相邻

    最后再用两个老师把她们分开


    什么,你说最后排男生?其实也可以做,只不过讨论起来比较复杂


    答案很大,高精度即可


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxl=10010,P=10000;
    using namespace std;
    int n,m;
    
    struct bign{
    	int v[maxl],len;
    	void del0(){while (len>1&&!v[len-1]) len--;}
    	void clear(){memset(v,0,sizeof(v)),len=1;}
    	bign operator *(const bign &b){
    		bign c;c.clear();
    		c.len=len+b.len;
    		for (int i=0;i<len;i++)
    			for (int j=0;j<b.len;j++){
    				c.v[i+j]+=v[i]*b.v[j];
    				if (c.v[i+j]>P) c.v[i+j+1]+=c.v[i+j]/P,c.v[i+j]%=P;
    			}
    		c.del0();return c;
    	}
    	bign operator +(const bign &b){
    		bign c;c.clear();
    		c.len=max(len,b.len)+1;
    		for (int i=0;i<c.len;i++){
    			c.v[i]+=v[i]+b.v[i];
    			if (c.v[i]>P) c.v[i+1]++,c.v[i]-=P;
    		}
    		c.del0();return c;
    	}
    	void write(){
    		printf("%d",v[len-1]);
    		for (int i=len-2;i>=0;i--) printf("%04d",v[i]);
    		puts("");
    	}
    };
    
    bign fact(int a,int b){
    	bign res;res.clear();
    	if (a>b) return res;
    	res.v[0]=1;
    	for (int i=a;i<=b;i++){
    		bign pp;pp.clear(),pp.v[0]=i;
    		res=res*pp;
    	}
    	return res;
    }
    bign A(int n,int m){
    	if (!m){
    		bign res;res.clear(),res.v[0]=1;
    		return res;
    	}
    	if (m>n){bign res;res.clear();return res;}
    	return fact(n-m+1,n);
    }
    //A(n,n)*(A(n+1,2)*A(n+3,m)+A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1))
    
    int main(){
    	scanf("%d%d",&n,&m);
    	bign ans=A(n,n)*(A(n+1,2)*A(n+3,m)+A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1));
    	ans.write();
    	return 0;
    }


  • 相关阅读:
    C语言_航模社第四节
    C语言_航模社第三节
    C语言交换两个变量的值
    C语言表达分段函数
    c语言_2017.10.22
    stm32_配置GPIO点亮led灯
    prteus8安装教程
    安装keil_5步骤
    nginx配置实现https的配置文件方法
    TortoiseGit 代码版本回退及返回
  • 原文地址:https://www.cnblogs.com/thythy/p/5493483.html
Copyright © 2011-2022 走看看