CodeForces 1288C
组合数简单应用
一般来说组合数简单应用难点在于怎么想到去构造组合数公式,一般在计数题中可能出现,计数题可能是组合数、计数DP。这题的难点就在于构造组合数公式
(m) 个 (a_i), (m) 个 (b_i)
(a_i leq b_i (1leq ileq n))
考虑这样的 (2m) 非下降序列:(a_1,a_2,...a_m,b_m,b_{m-1},...b_1) 即:(a_1leq a_2leq a_3...b_mleq b_{m-1}leq b_1) 可知这样是能够满足所有条件。。
那么就是要从 (n) 个数中选择 (2m) 个数满足非下降的条件,通过观察发现,只要你任取 (2m) 个数拍个序,必然满足非下降的条件,而且没有重复的情况。
这可以抽象成多重集组合数的组合数模型:
(ans = C_{n + r -1}^{n - 1} = C_{n + r -1} ^{r})
(r = 2m)
#include <bits/stdc++.h>
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define rep(I, N) for (int I = 1; I <= (N); ++I)
#define repp(I, N) for (int I = 0; I < (N); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORR(I, A, B) for (int I = (A); I >= (B); I--)
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
const int N = 2e5 + 5;
const double eps = 1e-7;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ULL;
typedef long double LD;
typedef pair<int,int> PII;
typedef vector<int> VI;
ll pow(ll a, ll b, ll m)
{
ll ans = 1;
a %= m;
while (b)
{
if (b & 1)
ans = (ans % m) * (a % m) % m;
b /= 2;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll inv(ll x, ll p) //x关于p的逆元,p为素数
{
return pow(x, p - 2, p);
}
ll C(ll n, ll m, ll p) //组合数C(n, m) % p
{
if (m > n)
return 0;
ll up = 1, down = 1; //分子分母;
for (int i = n - m + 1; i <= n; i++)
up = up * i % p;
for (int i = 1; i <= m; i++)
down = down * i % p;
return up * inv(down, p) % p;
}
ll Lucas(ll n, ll m, ll p)
{
if (m == 0)
return 1;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}
int main() {
ll n, m;
cin >> n >> m;
cout << Lucas(n + 2 * m - 1, 2 * m, mod) << endl;
return 0;
}