【2021牛客寒假第五场】B-比武招亲(上)排列组合
传送门: https://ac.nowcoder.com/acm/contest/9985/B
题意
思路
考 虑 最 大 值 和 最 小 值 贡 献 。 考虑最大值和最小值贡献。 考虑最大值和最小值贡献。
先
看
最
大
值
:
先看最大值:
先看最大值:
假
设
我
们
选
择
最
大
值
为
x
,
则
剩
下
m
−
1
个
位
置
只
能
选
不
超
过
x
的
数
字
假设我们选择最大值为x,则剩下m-1个位置只能选不超过x的数字
假设我们选择最大值为x,则剩下m−1个位置只能选不超过x的数字
题
目
表
示
排
完
序
之
后
本
质
不
同
!
\red{题目表示排完序之后本质不同!}
题目表示排完序之后本质不同!
所
以
就
是
在
不
超
过
x
的
数
字
中
任
意
重
复
选
择
m
−
1
个
并
且
生
成
不
递
减
序
列
的
个
数
。
所以就是在不超过x的数字中任意重复选择m-1个并且生成不递减序列的个数。
所以就是在不超过x的数字中任意重复选择m−1个并且生成不递减序列的个数。
没 错 , n 个 中 选 m 个 数 ( 可 重 复 ) 且 不 递 减 序 列 个 数 为 C n + m − 1 m 。 请 自 行 百 度 ! 没错,n个中选m个数(可重复)且不递减序列个数为C_{n+m-1}^{m}。请自行百度! 没错,n个中选m个数(可重复)且不递减序列个数为Cn+m−1m。请自行百度!
x
=
n
时
,
贡
献
为
n
∗
C
n
+
m
−
2
m
−
1
x=n时,贡献为n*C_{n+m-2}^{m-1}
x=n时,贡献为n∗Cn+m−2m−1
x
=
n
−
1
时
,
贡
献
为
(
n
−
1
)
∗
C
n
−
1
+
m
−
2
m
−
1
x=n-1时,贡献为(n-1)*C_{n-1+m-2}^{m-1}
x=n−1时,贡献为(n−1)∗Cn−1+m−2m−1
…
所 以 我 们 最 大 值 的 贡 献 就 是 所以我们最大值的贡献就是 所以我们最大值的贡献就是
∑ i = 1 n ( n − i + 1 ) ∗ C n − i + 1 + m − 2 m − 1 \sum_{i=1}^n(n-i+1)*C_{n-i+1+m-2}^{m-1} i=1∑n(n−i+1)∗Cn−i+1+m−2m−1
同 理 , 最 小 值 就 是 m − 1 个 位 置 必 须 选 择 不 小 于 x 的 数 字 , 贡 献 就 是 同理,最小值就是m-1个位置必须选择不小于x的数字,贡献就是 同理,最小值就是m−1个位置必须选择不小于x的数字,贡献就是
∑ i = 1 n i ∗ C n − i + 1 + m − 2 m − 1 \sum_{i=1}^ni*C_{n-i+1+m-2}^{m-1} i=1∑ni∗Cn−i+1+m−2m−1
这 两 个 式 子 是 我 化 简 过 后 的 。 难 点 就 是 不 递 减 序 列 个 数 是 多 少 。 \red{这两个式子是我化简过后的。难点就是不递减序列个数是多少。} 这两个式子是我化简过后的。难点就是不递减序列个数是多少。
两 个 减 一 减 得 : 两个减一减得: 两个减一减得:
∑ i = 1 n ( n − i + 1 ) ∗ C n − i + m − 1 m − 1 \sum_{i=1}^n(n-i+1)*C_{n-i+m-1}^{m-1} i=1∑n(n−i+1)∗Cn−i+m−1m−1
Code(44MS)
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
ll f[N], invF[N], inv[N];
void Init()
{
f[0] = f[1] = inv[0] = inv[1] = invF[0] = invF[1] = 1;
for(int i = 2;i < N; i++)
{
f[i] = f[i - 1] * i % mod;
inv[i] = mod - (mod / i) * inv[mod % i] % mod;
invF[i] = invF[i - 1] * inv[i] % mod;
}
}
ll C(ll m, ll n)
{
if(m < 0 || n < 0 || n > m)
return 0;
ll ans = f[m];
ans = ans * invF[n] % mod;
ans = ans * invF[m - n] % mod;
return ans;
}
//ll quick_pow(ll a, ll b) {
// ll ans = 1;
// while(b) {
// if(b & 1) ans = ans * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return ans % mod;
//}
void solve() {
Init();
ll n, m; cin >> n >> m;
ll ans = 0;
// C(n + m - 1, m) n个数中选m个不递减个数
for(ll i = 1;i <= n; i++) {
// cout << "个数:" << C(n - i + 1 + m - 1 - 1, m - 1) << endl;
ans = (ans + (n - 2 * i + 1) * C(n - i + m - 1, m - 1) % mod) % mod;
}
cout << (ans % mod + mod) % mod << endl;
}
signed main() {
solve();
}