• 【BZOJ2729】[HNOI2012]排队 组合数


    【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

    题解:先将老师与男生放到一起,然后将女生插到男生中间,方案书就是A(n+2,n+2)*A(n+3,m),再将老师相邻的方案减去,即将两个老师捆在一起,方案数为A(2,2)*A(n+1,n+1)*A(n+2,m)。

    然后就是丧心病狂的高精度时间了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    struct cbig
    {
    	int len;
    	int v[200000];
    	cbig(){len=0,memset(v,0,sizeof(v));}
    	cbig(int x)
    	{
    		len=0,memset(v,0,sizeof(v));
    		while(x)	v[++len]=x%10,x/=10;
    	}
    	void operator *= (int b)
    	{
    		int i;
    		for(i=1;i<=len;i++)	v[i]*=b;
    		for(i=1;i<=len;i++)	v[i+1]+=v[i]/10,v[i]%=10;
    		while(v[len+1])	len++,v[len+1]+=v[len]/10,v[len]%=10;
    	}
    	void operator -= (cbig b)
    	{
    		int i;
    		for(i=1;i<=b.len;i++)	v[i]-=b.v[i];
    		for(i=1;i<=len;i++)
    		{
    			if(v[i]<0)	v[i+1]+=v[i]/10,v[i]%=10;
    			if(v[i]<0)	v[i+1]--,v[i]+=10;
    		}
    		while(len&&!v[len])	len--;
    	}
    }ans1,ans2;
    void A(cbig &ret,int a,int b)
    {
    	for(int i=a-b+1;i<=a;i++)	ret*=i;
    }
    int main()
    {
    	int i,n,m;
    	scanf("%d%d",&n,&m);
    	ans1=cbig(1),A(ans1,n+2,n+2),A(ans1,n+3,m);
    	ans2=cbig(2),A(ans2,n+1,n+1),A(ans2,n+2,m);
    	ans1-=ans2;
    	if(!ans1.len)	printf("0");
    	else	for(i=ans1.len;i;i--)	printf("%d",ans1.v[i]);
    	return 0;
    }
  • 相关阅读:
    27:单词翻转
    c++自制锁机程序--两行代码
    19:字符串移位包含问题
    18:验证子串
    23:二维数组回形遍历
    Java获取程序或项目路径的常用方法
    java 、Android 提交参数转码问题
    java 上传图片 打水印
    使用getGenericSuperclass()和getActualTypeArguments()将DAO做成泛型
    zoj 1010 Area【线段相交问题】
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7367321.html
Copyright © 2020-2023  润新知