洛谷题单指南-组合数学与计数-P3223 [HNOI2012] 排队
原题链接:https://www.luogu.com.cn/problem/P3223
题意解读:n名男生m名女生2名老师排队,女生和老师都不能相邻,求方案数。
解题思路:
先不考虑老师是否相邻的情况:
将男生和老师先做排列A(n+2,n+2),再从n+3个空中选m个放置女生C(n+3,m),最后将女生做排列A(m,m),根据乘法原理一共A(n+2,n+2)C(n+3,m)A(m,m)。
再排除掉老师相邻的情况:
先将两个老师捆绑在一起,有2种,再将男生和捆绑在一起的老师做排列A(n+1,n+1),再从n+2个空中选m个放置女生C(n+2,m),最后将女生做排列A(m.m),根据乘法原理一共2A(n+1,n+1)C(n+2,m)A(m.m)。
因此,最终答案是A(n+2,n+2)C(n+3,m)A(m,m)-2A(n+1,n+1)C(n+2,m)A(m.m),
进一步化简:(n+2)!(n+3)!/(n-m+3)!-2(n+1)!(n+2)!/(n-m+2)!
继续化简:(n+1)!((n+2)(n+3)!/(n-m+3)!-2(n+2)!(n-m+3)/(n-m+3)!)
继续:(n^2+3n+2m)(n+1)!(n+2)!/(n-m+3)!
即:(n^2+3n+2m)A(n+1,n+1)A(n+2,m-1)
n,m最大2000,直接计算复杂度没问题,但是需要用高精度乘法。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m;
vector<int> mul(vector<int> &a, int b)
{
vector<int> res;
int t = 0;
for(int i = 0; i < a.size(); i++)
{
t += a[i] * b;
res.push_back(t % 10);
t /= 10;
}
while(t)
{
res.push_back(t % 10);
t /= 10;
}
return res;
}
int main()
{
vector<int> ans(1, 1);
cin >> n >> m;
ans = mul(ans,n * n + 3 * n + 2 * m);
for(int i = 0; i < n + 1; i++) ans = mul(ans, n + 1 - i);
for(int i = 0; i < m - 1; i++) ans = mul(ans, n + 2 - i);
for(int i = ans.size() - 1; i >= 0; i--) cout << ans[i];
return 0;
}
浙公网安备 33010602011771号