P3223 [HNOI2012]排隊
題目描述
某中學有 n 名男同學,m 名女同學和兩名老師要排隊參加體檢。他們排成一條直線,並且任意兩名女同學不能相鄰,
兩名老師也不能相鄰,那麼一共有多少種排法呢?(注意:任意兩個人都是不同的)
輸入格式
只有一行且為用空格隔開的兩個非負整數 n 和 m,其含義如上所述。
輸出格式
僅一個非負整數,表示不同的排法個數。注意答案可能很大。
輸入輸出樣例
輸入 #1
1 1
輸出 #1
12
說明/提示
對於 30% 的資料 n≤100
對於 100% 的資料 n≤2000
這道題的柿子好難啊(蒟蒻我只能爬)
首先,我們分兩種情況討論
-
當兩個老師之間是男生的時候。 這還是很簡單的
首先先將\(n\)個男生排好隊就是 \(A_{n}^{n}\)
此時產生了\(n+1\)個空,把兩位老師插進去就有\(A_{n+1}^{2}\)種方案
然後就會產生\(n+3\)個空 再把\(m\)個女生放進去就會有\(A_{n+3}^{m}\)種方案
那麼綜上第一種情況會有\(A_{n}^{n} \times A_{n+1}^{2} \times A_{n+3}^{m}\)
-
當由女生把老師隔開的時候,這種情況比較複雜,需要我們大力討論
首先,因為這個不管男生什麼事,那我們就可以先把男生先排好也就是\(A_{n}^{n}\)
然後,因為老師之間要是女生,所以我們可以把兩個老師和一個女生當成一個整體,
插入到\(n+1\)個空中,因為老師之間又是不同的,所以可以產生\(A_{2}^{2}\)
再加上從\(m\)個女生中選出一個的方案數為\(C_{m}^{1}\),就會有\(A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1}\)
至於剩下的\(m-1\)個女生直接插在\(n+2\)個空中就可以了,也就會產生\(A_{n+2}^{m-1}\)種方案
綜上第二種情況的方案數就為\(A_{n}^{n} \times A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1} \times A_{n+2}^{m-1}\)
最後的答案就是\(A_{n}^{n} \times A_{n+1}^{2} \times A_{n+3}^{m} + A_{n}^{n} \times A_{n+1}^{1} \times A_{2}^{2} \times C_{m}^{1} \times A_{n+2}^{m-1}\)
這個柿子其實還是可以化簡的,但是我忘了怎麼化了(大霧)
程式碼
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,m,len = 1;
long long ans[11000];
long long p = 100000000;
void mul(int x){
long long res = 0,num;
for(int i = 1; i <= len; i++){
num = ans[i] * x;
ans[i] = num % p + res;
res = num / p;//進位
}
if(res != 0){
len++;
ans[len] = res;
}
}
int main(){
scanf("%lld%lld",&n,&m);
ans[1] = 1;
mul(n+1);
mul(n*n+3*n+2*m);
for(int i = 1; i <= n; i++){//計算n的階乘
mul(i);
}
for(int i = n-m+4; i <= n+2; i++){//計算n+2的階乘除以n-m+3的階乘
mul(i);
}
cout<<ans[len];
while(--len){
printf("%08lld",ans[len]);
}
return 0;
}
//拜託不要卡cincout 遠古時期的程式碼