[HNOI2012]排队
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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;
}