[HNOI2012] 排队
[HNOI2012] 排队
0x01 题意
某中学有 n名男同学,m名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)
0x02 解
小学数学题
补集思想
插空法
"不邻问题"插空法,即在解决对于某几个元素要求不相邻的问题时,先将其它元素排好,再将指定的不相邻的元素插入已排好元素的间隙或两端位置,从而将问题解决的策略。
老师不相邻=不考虑老师相邻-老师相邻
- 不考虑老师相邻
老师与男同学等价,用插空法解决
共有
\[A^{n+2}_{n+2}\times A^m_m\times C^m_{n+3}
\]
种方法
- 老师相邻
将老师捆绑起来(bushi ,看做整体与男同学等价,用插空法解决
共有
\[A^2_2\times A^{n+1}_{n+1}\times A^m_m\times C^m_{n+2}
\]
种方法
两者作差即为答案
化简得
\[\prod_{i=n+4-m}^{n+2}i\times(n+1)!\times(n^2+3n+2m)
\]
还有:高精
0x03 代码
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m;
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i ++ ){
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main(){
cin>>n>>m;
int res=n*n+3*n+2*m;
vector<int> ans;
ans.push_back(1);
for(int i=1;i<=n+1;i++) ans=mul(ans,i);
for(int i=n+4-m;i<=n+2;i++) ans=mul(ans,i);
ans=mul(ans,res);
for(int i=ans.size()-1;i>=0;i--) cout<<ans[i];
return 0;
}