题目大意
给定三个正整数 N , L , R N, L, R N,L,R,统计长度在 1 1 1 到 N N N 之间,元素大小都在 L L L 到 R R R 之间的单调不降序列的数量。输出答案对 1 e 6 + 3 1e6 + 3 1e6+3 取模的结果。
解题思路
思路一
令 m = R − L + 1 m=R-L+1 m=R−L+1,那么问题可以转化为 m m m 个盒子, n n n 个小球放入其中,盒子可以为空。此时采用隔板法, m − 1 m-1 m−1 个隔板即可将小球分割为 m m m 份;先将隔板视为小球,然后分为 m m m 份(每份最少一个)接着每一份里面拿走一个,就是该问题的等价情况。不难发现对应的是 n + m − 1 n+m-1 n+m−1 个小球分为 m m m 份,每份最少一个的方案数,即为 C n + m − 1 n C_{n+m-1}^n Cn+m−1n。
思路二
假设是从 n n n 个数中选出 m m m 个数,只考虑如何选,那么选好之后排序就是一种方案。
- 若组成单调递增序列,当我们选择了第一个数的时候,后面有 n − 1 n - 1 n−1 种选择,选择第二个数的时候,后面有 n − 2 n - 2 n−2 种选择…这样最终的方案数目是 n ∗ ( n − 1 ) ∗ . . . ∗ ( n − m + 1 ) = C n m n*(n - 1) *...*(n - m + 1) = C_n^m n∗(n−1)∗...∗(n−m+1)=Cnm。
- 若组成单调不降序列,选择第一个数时后面实际上有 n + m − 1 n + m - 1 n+m−1 种数可以选择(加上了 m − 1 m-1 m−1 个可重复的,选择第二个数时后面有 n + m − 2 n + m - 2 n+m−2 个数可以选择…这样最终的方案数目显然是 C n + m − 1 m C_{n + m - 1}^m Cn+m−1m 。
综上,设 m = R − L + 1 m = R-L+1 m=R−L+1,则本题的答案是 C m 1 + C m + 1 2 + C m + 2 3 + . . . + C m + n − 1 n C_{m}^1 + C_{m+1}^2 +C_{m+2}^3+ ... + C_{m + n - 1}^n Cm1+Cm+12+Cm+23+...+Cm+n−1n,由于范围过大显然需要化简为一个公式:
C m 1 + C m + 1 2 + C m + 2 3 + . . . + C m + n − 1 n = C m + n n − 1 C_{m}^1 + C_{m+1}^2 + C_{m+2}^3+... + C_{m + n - 1}^n = C_{m + n} ^n - 1 Cm1+Cm+12+Cm+23+...+Cm+n−1n=Cm+nn−1
证明:将这 n n n 个组合数前面几项写在纸上,发现它是杨辉三角的一个对角线,根据 C n m = C n − 1 m + C n − 1 m − 1 C_n^m=C_{n-1}^m+C_{n-1}^{m-1} Cnm=Cn−1m+Cn−1m−1,先加上一个 C m 0 C_m^0 Cm0 然后减一,这样两两向下递推可以不断约项,最后得到 C m + n n − 1 C_{m+n}^n - 1 Cm+nn−1。
#include <bits/stdc++.h>
using namespace std;
#define ENDL "\n"
typedef long long ll;
const int maxn = 1e6 + 10;
const int Mod = 1e6 + 3;
ll qkp(ll x, ll n, ll p) {
ll ans = 1;
x %= p;
while (n) {
if (n & 1) ans = ans * x % p;
x = x * x % p;
n >>= 1;
}
return ans;
}
ll inv(ll x, ll p) { //求逆元
return qkp(x, p - 2, p);
}
ll cal(ll n, ll m, ll p) {
if (m > n) return 0;
ll u = 1, d = 1;
for (int i = n - m + 1; i <= n; i++) u = u * i % p;
for (int i = 1; i <= m; i++) d = d * i % p;
return u * inv(d, p) % p;
}
ll lucas(ll n, ll m, ll p) {
if (!m) return 1;
return cal(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
ll n, l, r;
cin >> T;
while(T--) {
cin >> n >> l >> r;
ll m = r - l + 1;
cout << (lucas(n + m, n, Mod) - 1 + Mod) % Mod << endl;
}
return 0;
}