「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} \]

很显然过不了,考虑化简。。。

要运用到的组合恒等式:

  1. \(\sum\limits_{i=0}^{n} \binom{i}{k} = \binom{n+1}{k+1}\)
  2. \(\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 <cstdio>

#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;
}
posted @ 2021-12-13 21:55  PoisonNNN  阅读(28)  评论(0编辑  收藏  举报