[HNOI2012] 排队

[HNOI2012] 排队

0x01 题意

某中学有 n名男同学,m名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)

0x02 解

小学数学题

补集思想

插空法

​ "不邻问题"插空法,即在解决对于某几个元素要求不相邻的问题时,先将其它元素排好,再将指定的不相邻的元素插入已排好元素的间隙或两端位置,从而将问题解决的策略。

老师不相邻=不考虑老师相邻-老师相邻

  1. 不考虑老师相邻

老师与男同学等价,用插空法解决

共有

\[A^{n+2}_{n+2}\times A^m_m\times C^m_{n+3} \]

种方法

  1. 老师相邻

将老师捆绑起来(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;
}
posted @ 2021-02-27 20:43  wsy_jim  阅读(160)  评论(0编辑  收藏  举报