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

题解Here!

这个题比较烦人。
分类讨论一下:

  • 两个老师中间只站着一个女生。

这时$ ext{两老师+一女生}$应该看做一个整体。
对应答案就是:
$$A(n,n) imes A(n+1,1) imes A(2,2) imes A(n+2,m-1)$$

  • 两个老师中间不止站一个女生。

这时中间一定有男生,于是随便插空就好了。
对应答案就是:
$$A(n,n) imes A(n+1,2) imes A(n+3,m)$$
然后题目中也说了,答案可能很大,所以。。。

高精度

还是压了$5$位的高精度。。。

但是我上次不是立了个$flag$——不再写高精了吗?

嘿嘿,这次我是直接复制的高精模板哈哈哈!

不过我以后还是不写高精,只复制模板!

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 10010
#define L 100000
using namespace std;
int n,m;
struct Bignum{
	int len;
	long long val[MAXN];
	void clean(){
		len=0;
		memset(val,0,sizeof(val));
	}
	void init(int k){
		clean();
		len=1;
		val[1]=k;
	}
	void write(){
		printf("%lld",val[len]);
		for(int i=len-1;i>=1;i--)printf("%05lld",val[i]);
		printf("
");
	}
	friend Bignum operator +(Bignum x,Bignum y){
		Bignum s;
		s.clean();
        s.len=max(x.len,y.len)+12;
        for(int i=1;i<=s.len;i++){
            s.val[i]+=x.val[i]+y.val[i];
            s.val[i+1]+=s.val[i]/L;
            s.val[i]%=L;
        }
		for(int i=1;i<=s.len;i++){
			s.val[i+1]+=s.val[i]/L;
			s.val[i]%=L;
		}
		while(s.len&&!s.val[s.len])s.len--;
        return s;
    }
    friend Bignum operator *(Bignum x,Bignum y){
    	Bignum s;
    	s.clean();
    	s.len=x.len+y.len+12;
    	for(int i=1;i<=x.len;i++)
    	for(int j=1;j<=y.len;j++){
    		s.val[i+j-1]+=x.val[i]*y.val[j];
    		s.val[i+j]+=s.val[i+j-1]/L;
    		s.val[i+j-1]%=L;
		}
		for(int i=1;i<=s.len;i++){
			s.val[i+1]+=s.val[i]/L;
			s.val[i]%=L;
		}
		while(s.len&&!s.val[s.len])s.len--;
		return s;
    }
}ans;
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
Bignum A(int n,int m){
	Bignum s,x;
	s.clean();
	if(m>n)return s;
	s.init(1);
	if(!m)return s;
	for(int i=n-m+1;i<=n;i++){
		x.clean();x.init(i);
		s=s*x;
	}
	return s;
}
inline void solve(int n,int m){
	ans=A(n,n)*A(n+1,2)*A(n+3,m)+A(n,n)*A(n+1,1)*A(2,2)*A(m,1)*A(n+2,m-1);
	ans.write();
}
int main(){
	n=read();m=read();
	solve(n,m);
    return 0;
}
原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9512278.html