Hz的计数问题总结

前言

看见 mod1e9 + 7 就跪了,遂写一篇博客把所有的计数问题、组合数学问题都记录下来...

正片

E. Girl Permutation

Some permutation of length n n n is guessed.

You are given the indices of its prefix maximums and suffix maximums.

Recall that a permutation of length k k k is an array of size k k k such that each integer from 1 1 1 to k k k occurs exactly once.

Prefix maximums are the elements that are the maximum on the prefix ending at that element. More formally, the element a i a_i ai is a prefix maximum if a i > a j a_i > a_j ai>aj for every j < i j < i j<i.

Similarly, suffix maximums are defined, the element a i a_i ai is a suffix maximum if a i > a j a_i > a_j ai>aj for every j > i j > i j>i.

You need to output the number of different permutations that could have been guessed.

As this number can be very large, output the answer modulo 1 0 9 + 7 10^9 + 7 109+7.

感觉好经典的模型,没有想出来是因为一直在纠结两部分分开处理的情况下发生重复怎么办。。

实际上我们可以发现,只要先用组合数 C C C 选出一部分数字放在左边,剩下的部分放在右边,则两部分一定不会发生重复

但是一定存在一种方案使得它们摆放起来满足方案吗?

答案是YES,这个自己手玩一下就可以发现了,数量够的情况下,排列中的数字两两不同,则总会存在一种方式使得摆放是正确的。

因此分开考虑是合法的。

接下来就是单独考虑左边,我们从右向左(从高到低)遍历 p p p 数组,可以发现每两个相邻的下标中间存在着一些 gap,我们选择一些比 p[i] 和 p[i + 1] 都要小的数字填充这些 gap(全排列),所以就是comb(p[i + 1] - 2, p[i + 1] - p[i] - 1);

这里的 -2 是因为最大值和次大值已经放在了 p[i] 和 p[i + 1] 的位置,故,必须-2.

最后代码如下:

cpp 复制代码
int qpow(int a, int k) {
	a %= mod;
	i64 res = 1 % mod;
	while(k) {
		if (k & 1) res = (i64)res * a % mod;
		a = (i64)a * a % mod;
		k >>= 1;
	}
	return res;
}

int inv(int x) {
	return qpow(x, mod - 2);
}
struct Comb {
    int n;
    vector<int> fac, invfac, pow2;
    Comb(): n(0) {}
    Comb(int _n): n(0) { init(_n); }

    void init(int m) {
        if (m <= n) return;
        fac.resize(m + 1);
        invfac.resize(m + 1);
        pow2.resize(m + 1);

        pow2[0] = 1;
        for (int i = 1; i <= m; i++) {
            pow2[i] = (int)(pow2[i - 1] * 2LL) % mod;
        }
        int start = n > 0 ? n + 1 : 1;
        if (n == 0) {
            fac[0] = invfac[0] = 1;
        }
        for (int i = start; i <= m; i++) {
            fac[i] = (int)((i64)fac[i - 1] * i % mod);
        }
        invfac[m] = qpow(fac[m], mod-2);
        for (int i = m; i > (n == 0 ? 1 : n); i--) {
            invfac[i - 1] = (int)((i64)invfac[i] * i % mod);
        }
        n = m;
    }

    // fac[m]
    int F(int m) {
        if (m > n) init(2 * m);
        return fac[m];
    }
    // invfac[m]
    int iF(int m) {
        if (m > n) init(2 * m);
        return invfac[m];
    }
    // inv[m] = m^{-1}
    int inv(int m) {
        return qpow(m, mod - 2);
    }
    // pow(2, n)
    int P2(int m) {
        if (m <= n) return pow2[m];
        return qpow(2, m);
    }
    // A(n, m) = n! / (n - m)!
    int A(int n_, int m_) {
        if (m_ < 0 || m_ > n_) return 0;
        if (n_ > n) init(2 * n_);
        return (int)( (i64)fac[n_] * invfac[n_ - m_] % mod );
    }
    // C(n, m) = n! / (m! * (n - m)!)
    int C(int n_, int m_) {
        if (m_ < 0 || m_ > n_) return 0;
        if (n_ > n) init(2 * n_);
        return (int)((i64)fac[n_] * invfac[m_] % mod * invfac[n_ - m_] % mod );
    }
};
Comb comb(1e6);

void solve()
{
    int n, m1, m2;
    cin >> n >> m1 >> m2;
    vector<int> p(m1 + 1), s(m2 + 1);
    for (int i = 1; i <= m1; i++) {
        cin >> p[i];
    }
    for (int i = 1; i <= m2; i++) {
        cin >> s[i];
    }
    if (s[m2] != n || p[1] != 1 || s[1] != p[m1]) {
        cout << 0 << endl;
        return;
    }
    int ans = comb.C(n - 1, p.back() - 1);
    for (int i = m1 - 1; i >= 1; i--) {
        int g = p[i + 1] - p[i] - 1;
        (ans *= comb.C(p[i + 1] - 2, g) * comb.F(g) % mod) %= mod;
    }
    for (int i = 1; i <= m2 - 1; i++) {
        int g = s[i + 1] - s[i] - 1;
        (ans *= comb.C(n - s[i] - 1, g) * comb.F(g) % mod) %= mod;
    }
    cout << ans << endl;
}
相关推荐
她说彩礼65万5 小时前
C# 反射
java·算法·c#
练习时长一年5 小时前
LeetCode热题100(搜索插入位置)
数据结构·算法·leetcode
hz_zhangrl5 小时前
CCF-GESP 等级考试 2025年9月认证C++六级真题解析
c++·算法·青少年编程·程序设计·gesp·2025年9月gesp·gesp c++六级
凌睿马5 小时前
关于复杂数据结构从MySQL迁移到PostgreSQL的可行性
数据结构·数据库·mysql
喇一渡渡5 小时前
Java力扣---滑动窗口(1)
java·算法·排序算法
net3m335 小时前
雅特力单片机用串口USART_INT_TDE中断比用USART_INT_TRAC的 发送效率要高
java·开发语言·算法
@我漫长的孤独流浪6 小时前
程序综合实践第十二周-二叉树
算法·深度优先·图论
啊阿狸不会拉杆6 小时前
《数字图像处理》第 3 章 - 灰度变换与空间滤波
图像处理·人工智能·算法·计算机视觉·数字图像处理
执笔论英雄6 小时前
【RL 】Ray 支持RDMA
算法