[HNOI2012]排队

[HNOI2012]排队

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 608   Solved: 284
[ Submit][ Status]

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


老师是很特殊的!首先只有两个,而且只是老师之间不能相邻,很像男生!同样转换一个角度,考虑容斥原理,首先将老师考虑成男生再将相邻的情况减掉。相邻的情况怎么统计?捆绑法(将两个老师捆在一起)看做一个男生。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct Tbig{
	static const int maxn = 3000, limit = 10000, width = 4;
	int len, a[maxn];
	int& operator [] (int p){ return a[p]; }
	void clear(){ memset(a, 0, sizeof(a)); }
	void del0(){ while (!a[len - 1] && len > 1) len --; }
	Tbig (int x = 0){ *this = x; }
	Tbig (const char *p){ *this = p; }
	Tbig& operator = (int x){
		clear(); len = x?0:1;
		for (; x; x /= limit) a[len ++] = x % limit;
		return *this;
	}
	Tbig& operator = (const char *p){
		clear(); len = 0;
		for (int i = strlen(p) - 1; i >= 0; i -=width){
			int now = 0;
			for (int j = max(0, i - width + 1); j <= i; j ++) now = now * 10 + p[j] - '0';
			a[len ++] = now;
		} 
		return *this;
	}
	Tbig& operator += (Tbig b){
		len = max(len, b.len) + 1;
		for (int i = 0; i < len; i ++) a[i] += b[i], a[i + 1] += a[i] / limit, a[i] %= limit;
		del0(); return *this;
	}
	Tbig& operator -= (Tbig b){
		for (int i = 0; i < len; i ++){a[i] -= b[i]; if (a[i] < 0) a[i + 1] --, a[i] += limit; }
		del0();return *this;
	}
	Tbig& operator *= (Tbig b){
		Tbig c = *this; clear();
		len = b.len + c.len + 1;
		for (int i = 0; i <= b.len; i ++)
			for (int j = 0; j <= c.len; j ++)
				a[i + j] += b[i] * c[j], a[i + j + 1] += a[i + j] / limit, a[i + j] %= limit;
		del0(); return *this;
	}
	Tbig& operator /= (int b){
		for (int i = len - 1; i > 0; i --)
			a[i - 1] = limit * (a[i] % b), a[i] /= b, a[0] /= b;
		del0(); return *this;
	}
		
	bool operator < (Tbig b){
		if (len != b.len) return len < b.len;
		for (int i = len - 1; i >= 0; i --) if (a[i] != b[i]) return a[i] < b[i];
		return false;
	}
	bool operator == (Tbig b){
		if (len != b.len) return false;
		for (int i = len - 1; i >= 0; i --) if (a[i] != b[i]) return false;
		return true;
	}
	bool operator <= (Tbig b){ return *this < b || *this == b; }
	bool operator > (Tbig b){ return b < *this; }
	bool operator >= (Tbig b){ return b < *this || *this == b; }
};

Tbig operator + (Tbig a, Tbig b){ return a += b; }
Tbig operator - (Tbig a, Tbig b){ return a -= b; }
Tbig operator * (Tbig a, Tbig b){ return a *= b; }
Tbig operator / (Tbig a, int b){ return a /= b; }
void read(Tbig &x){
	char ch[11111];
	scanf("%s", ch);
	x = ch;
}
void write(Tbig x){
	printf("%d", x[x.len - 1]);
	for (int i = x.len - 2; i >= 0; i --) printf("%04d", x[i]);
}
Tbig jc(int n){
	Tbig a = 1;
	for (int i = 1; i <= n; i ++) a *= i;
	return a;
}
Tbig A(int n, int m){
	Tbig a = 1;
	for (int i = n; i >= n - m + 1; i --) a *= i;
	return a;
}
int n, m;
void work(){
	cin >> n >> m;
	Tbig ans = 0;
	if (n + 3 >= m)
		ans = jc(n + 2) * A(n + 3, m) - 2 * jc(n + 1) * A(n + 2, m);
	write(ans);
}
int main(){
	work();
	return 0;
}


你可能感兴趣的:([HNOI2012]排队)