[CF1288C] Two Arrays - 组合数学

给定一个数 \(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;
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12536823.html