1. 程式人生 > 其它 >「Solution」CodeChef - Count Sequences

「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;
}