「Solution」CodeChef - Count Sequences
Problem
Link
题意:给定三个正整数 \(N,L,R\) ,统计长度在 \(1\) 到 \(N\) 之间,元素大小在 \([L,R]\) 之间的单调不下降序列的数量。答案对 \(10^6+3\) 取模。( \(1 \leq N,L,R \leq10^9\) )
Solution
考虑推出方案数的式子。
先把问题简化:在序列长度为 \(M\) 时,方案数是多少。
可以枚举用到了 \(x\) 个不同的数,我们在 \([L,R]\) 中选 \(x\) 个的方案数就是 \(\binom{R-L+1}{x}\) 个。
确定了用到的数,则这 \(x\) 个数的顺序是确定的,即从小到大。又因为序列的性质是单调不下降,即每个数出现的次数 \(\geq 1\) 。
可以将问题转化为经典的小球问题:
- 有 \(x\) 个相同的盒子,将 \(M\) 个相同的小球放进盒子中,盒子不能为空的方案数。
解释一下:小球即代表序列的位置,显然相同。盒子即代表填的数,由于不同的数在序列中的顺序已经确定,所以也是相同的。盒子不能为空是因为我们相当于枚举了用了哪些数,为了不重复,每个必须用。
这个问题,可以用隔板法解决,想象成 \(x-1\) 个板,将 \(M\) 个小球间隔成 \(x\) 段,每段有唯一确定的盒子来放。由于盒子不为空,所以将板任意插在 \(M-1\) 个空隙中。
所以方案数为 \(\binom{M-1}{x-1}\) 。
因此可以得到对于原问题的总方案数:
\[Ans=\sum\limits_{i=1}^{N} \sum\limits_{j=1}^{R-L+1} \dbinom{R-L+1}{j} \dbinom{i-1}{j-1} \]很显然过不了,考虑化简。。。
要运用到的组合恒等式:
- \(\sum\limits_{i=0}^{n} \binom{i}{k} = \binom{n+1}{k+1}\)
- \(\sum\limits_{k=0}^{n} \binom{n}{k} \binom{m}{k} = \binom{n+m}{n}\)
证明会在另一个组合恒等式的 blog 里。(还没写)
先交换两个 sigma ,然后改变一下和式上限下限,用上上面两个结论就行了。
$Ans=\sum\limits_{i=1}^{N} \sum\limits_{j=1}^{R-L+1} \dbinom{R-L+1}{j} \dbinom{i-1}{j-1} $
$=\sum\limits_{j=1}^{R-L+1} \sum\limits_{i=1}^{N} \dbinom{R-L+1}{j} \dbinom{i-1}{j-1} $
$=\sum\limits_{j=1}^{R-L+1} \dbinom{R-L+1}{j} \sum\limits_{i=1}^{N} \dbinom{i-1}{j-1} $
$=\sum\limits_{j=1}^{R-L+1} \dbinom{R-L+1}{j} \sum\limits_{i=0}^{N-1} \dbinom{i}{j-1} $
$=\sum\limits_{j=1}^{R-L+1} \dbinom{R-L+1}{j} \dbinom{N}{j} $
$=[\sum\limits_{j=0}^{R-L+1} \dbinom{R-L+1}{j} \dbinom{N}{j}] - \dbinom{R-L+1}{0} \dbinom{N}{0} $
$=[\sum\limits_{j=0}^{R-L+1} \dbinom{R-L+1}{j} \dbinom{N}{j}] - 1 $
\(=\dbinom{N+R-L+1}{R-L+1} - 1\)
由于这里数据有 \(10^9\) 直接求组合数不可能,因为这里的模数不大且是个素数,所以就可以愉快的用一下 \(\text{Lucas}\) 定理啦。
Code
\\by Poison
#include
#define Mod 1000003
#define Maxn 2000010
#define LL long long
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)
int T;
LL inv[Maxn + 5], fac[Maxn + 5];
void Init () {
fac[0] = 1;
rep (i, 1, Maxn) fac[i] = fac[i - 1] * i % Mod;
inv[1] = 1;
rep (i, 2, Maxn) inv[i] = (Mod - Mod / i) * inv[Mod % i] % Mod;
inv[0] = 1;
rep (i, 1, Maxn) inv[i] = inv[i - 1] * inv[i] % Mod;
}
LL C (int a, int b) {
if (a < b) return 0;
return fac[a] * inv[b] % Mod * inv[a - b] % Mod;
}
LL Lucas (int n, int m) {
if (!n && !m) return 1;
return C (n % Mod, m % Mod) * Lucas (n / Mod, m / Mod) % Mod;
}
int main () {
scanf ("%d", &T);
Init ();
while (T --) {
int n, l, r;
scanf ("%d %d %d", &n, &l, &r);
printf ("%lld\n", (Lucas (n + r - l + 1, r - l + 1) - 1 + Mod) % Mod);
}
return 0;
}