给定一个数 \(n\) 和一个数 \(m\),让构建两个数组 \(a\) 和 \(b\) 满足条件
- 数组中所有元素的取值在 \([1, n]\) 之间
- \(a\) 和 \(b\) 数组长度是 \(m\)
- \(a\) 数组是单调不降的,\(b\) 数组是单调不增
- 任意的位置 \(i\),有 \(a_i \leq b_i\)
Solution
首先很容易想到将 \(b\) 翻转后接在 \(a\) 的后面,那么问题就转化为用 \([1,n]\) 填一个长度为 \(2m\) 的序列,使其单调不降的方案数
DP 解法
设 \(f[i][j]\) 表示填一个 \(i\) 长度的序列,最后一位为 \(j\) 的方案数,于是
\[ f[i][j]=f[i-1][j]+f[i-1][j-1] \]
暴力转移即可,时间复杂度 \(O(nm)\)
组合
等价于求 \(x_1+x_2+...+x_n=2m\) 的解的方案数,于是考虑隔板法,答案为 \(C_{2m+n-1}^{n-1}\)
时间复杂度 \(O(n)\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
int qpow(int p,int q) {
return (q&1 ? p : 1) * (q?qpow(p*p%mod,q/2):1) % mod;
}
int inv(int p) {
return qpow(p,mod-2);
}
int frac(int p) {
int res = 1;
for(int i=2;i<=p;i++) res=res*i%mod;
return res;
}
int n,m;
signed main() {
cin>>n>>m;
cout<<frac(2*m+n-1)*inv(frac(n-1))%mod*inv(frac(2*m))%mod;
}