C. Two Arrays(1288C)(组合数)

C. Two Arrays(1288C)(组合数)


题目来源:C. Two Arrays


题意:

给出 n 和 m,构造两个数组 a 和 b,满足以下条件

  • 数组长度均为 m
  • 两数组的值域为 1 - n
  • a 数组按非降序排序
  • b 数组按非升序排序
  • a[i] <= b[i]

思路:

根据题意我们可以知道,a升序,b降序,并且 a[1] >= b[1],那么我们可以将b数组翻转一下,并将它们连接起来

将新的两个数组先连接起来组成 b[m], b[m - 1], … , b[1], a[1], a[2], … , a[m],此时的数组是非降序的

此时相当于在 1 - n 中选出 2 * m 个数,并且每个数可以被选多次
反向思考一下,就变成将 2 * m 个球投入 n 个篮子里,篮子允许为空
先让每个篮子至少拥有一个球
问题就变成了将 2 * m + n 个球投入 n 个篮子里,每个篮子至少有一个球
利用隔板法,将 n - 1 个板插入 2 * m + n - 1 个空隙中
因此答案为 C(2 * m + n - 1, n - 1)

思路来源
  • 最后为什么直接插板就行,而不用考虑排序的问题(从前往后插板所隔开的球不能减少)
    • 因为我们构成的新数组数非递减的,所以我们只需要找出 2 * m 个数即可,将它们存入新数组时,就相当于会自动排序了

AC代码

#include <bits/stdc++.h>
#define endl "\n"
#define rep(i, m, n) for (int i = (m); i <= (n); ++i)
#define rrep(i, m, n) for (int i = (m); i >= (n); --i)
#define IOS ios::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e3 + 50, mod = 1e9 + 7;
int n, m;
// 2 * m + n 个球,放入 n 个盒子,每个盒子至少一个
// 插板法相当于有 2 * m + n - 1 个空,插 n - 1 个板
// C(2 * m + n - 1, n - 1) = (2 * m + n - 1)! / (n - 1)! / (2 * m)!
ll qpow(int a, int b) {
	ll res = 1; a %= mod;
	while (b) {
		if (b & 1) res = (ll)res * a % mod;
		a = (ll)a * a % mod; b >>= 1;
	}
	return res;
}
ll C(int a, int b) {
	ll up = 1, down = 1;
	for (int i = 0; i < b; ++i) {
		up = up * (a - i) % mod;
		down = down * (b - i) % mod;
	}
	down = qpow(down, mod - 2); // 计算逆元
	return up * down % mod;
}
void solve() {
	cin >> n >> m;
	cout << C(2 * m + n - 1, n - 1) << endl;
}
int main() {
	solve();
	return 0;
}

END

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值