1. 程式人生 > 實用技巧 >P3223 [HNOI2012]排隊

P3223 [HNOI2012]排隊

題目描述

某中學有 n 名男同學,m 名女同學和兩名老師要排隊參加體檢。他們排成一條直線,並且任意兩名女同學不能相鄰,

兩名老師也不能相鄰,那麼一共有多少種排法呢?(注意:任意兩個人都是不同的)

輸入格式

只有一行且為用空格隔開的兩個非負整數 n 和 m,其含義如上所述。

輸出格式

僅一個非負整數,表示不同的排法個數。注意答案可能很大。

輸入輸出樣例

輸入 #1

1 1

輸出 #1

12

說明/提示

對於 30% 的資料 n≤100

對於 100% 的資料 n≤2000

這道題的柿子好難啊(蒟蒻我只能爬

首先,我們分兩種情況討論

  1. 當兩個老師之間是男生的時候。 這還是很簡單的

    首先先將\(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}\)

  2. 當由女生把老師隔開的時候,這種情況比較複雜,需要我們大力討論

    首先,因為這個不管男生什麼事,那我們就可以先把男生先排好也就是\(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 遠古時期的程式碼