ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

洛谷题单指南-组合数学与计数-P3223 [HNOI2012] 排队

洛谷题单指南-组合数学与计数-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;
}

 

返回列表