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

 

posted @ 2025-11-25 15:50  hackerchef  阅读(0)  评论(0)    收藏  举报