题目-序列统计

在这里插入图片描述

问题分析

尝试枚举序列长度 k k k, 当 k k k固定之后, 有多少个单调不下降序列, 并且所有数字在 [ L , R ] [L, R] [L,R]之间

因为数字之间大小是相对的, 可以映射 [ 0 , R − L ] [0, R - L] [0,RL], 并且数字是单调不下降的

那么有序列
0 ≤ a 1 ≤ a 2 . . . ≤ a k ≤ R − L 0 \le a_1 \le a_2 ... \le a_k \le R - L 0a1a2...akRL
x 1 = a 1 x_1 = a_1 x1=a1, x 2 = a 2 − a 1 x_2 = a_2 - a_1 x2=a2a1, x k = a k − a k − 1 x_k = a_k - a_{k - 1} xk=akak1

问题就转化成了 x i ≥ 0 x_i \ge 0 xi0条件下
x 1 + x 2 + . . . + x k ≤ R − L x_1 + x_2 + ... + x_k \le R - L x1+x2+...+xkRL
不定方程的非负整数解的个数

因为每个 x i ≥ 0 x_i \ge 0 xi0不好操作, 令 y i = x i + 1 y_i = x_i + 1 yi=xi+1, 其中 y i ≥ 1 y_i \ge 1 yi1

y 1 + y 2 + . . . + y k ≤ R − L + k y_1 + y_2 + ... + y_k \le R - L + k y1+y2+...+ykRL+k

如果是等式, 那么 k k k个变量需要放置 k − 1 k - 1 k1个隔板, 但是这里是 ≤ \le , 因此可以放置 k k k个隔板

也就是说最后一个隔板到最后一个小球的长度是 R − L + k − t R - L + k - t RL+kt, t t t是实际的和

当前 k k k的方案数 C R − L + k k C_{R - L + k} ^ k CRL+kk

那么答案是 ∑ k = 1 N C R − L + k k \sum _{k = 1} ^ N C_{R - L + k} ^ k k=1NCRL+kk, 令 m = R − L m = R - L m=RL

求和展开得到
C m + 1 1 + C m + 2 2 + . . . + C m + n n C_{m + 1} ^ 1 + C_{m + 2} ^ 2 +... + C_{m + n} ^ n Cm+11+Cm+22+...+Cm+nn

由组合恒等式 C a b = C a a − b C_a ^ b = C_a ^ {a - b} Cab=Caab得到

C m + 1 m + C m + 2 m + . . . + C m + n m C_{m + 1} ^ m + C_{m + 2} ^ m + ... + C_{m + n} ^ m Cm+1m+Cm+2m+...+Cm+nm

由组合恒等式 C a b = C a − 1 b + C a − 1 b − 1 C_a ^ b = C_{a - 1} ^ b + C_{a - 1} ^ {b - 1} Cab=Ca1b+Ca1b1得到

C m + 1 m + 1 + C m + 1 m + C m + 2 m + . . . + C m + n m − 1 C_{m + 1} ^ {m + 1} + C_{m + 1} ^ m + C_{m + 2} ^ m + ... + C_{m + n} ^ m - 1 Cm+1m+1+Cm+1m+Cm+2m+...+Cm+nm1

整理得到

C m + 2 m + 1 + C m + 2 m + . . . + C m + n m − 1 C_{m + 2} ^ {m + 1} + C_{m + 2} ^ m + ... + C_{m + n} ^ m - 1 Cm+2m+1+Cm+2m+...+Cm+nm1

两项两项合并, 最终得到

C m + n m + 1 + C m + n m − 1 = C m + n + 1 m + 1 − 1 C_{m + n} ^ {m + 1} + C_{m + n} ^ m - 1 = C_{m + n + 1} ^ {m + 1} - 1 Cm+nm+1+Cm+nm1=Cm+n+1m+11

最终的结果
a n s = C R − L + N + 1 R − L + 1 − 1 ans = C_{R - L + N + 1} ^ {R - L + 1} - 1 ans=CRL+N+1RL+11

算法步骤

线性方程和线性不定方程正整数解的个数都可以使用隔板法解决
观察数据范围, R , L ≤ 1 0 9 R, L \le 10 ^ 9 R,L109比较大, 但是取模的数字很小 1 0 6 + 3 10 ^ 6 + 3 106+3, 可以使用 l u c a s lucas lucas定理计算组合数

代码实现

注意计算阶乘的逆元的时候 i i i 1 1 1开始循环, 并且在 g e t get get函数过程中需要进行取模

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 1e6 + 10, MOD = 1e6 + 3;

int n, l, r;
LL fact[N], infact[N];

LL q_pow(LL a, LL b, LL mod) {
   
    LL ans = 1;
    a %= mod;
    while (b) {
   
        if (b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

void init() {
   
    fact[0] = 1;
    infact[0] = q_pow(fact[0], MOD - 2, MOD);
    for (int i = 1; i < N; ++i) {
   
        fact[i] = fact[i - 1] % MOD * i % MOD;
        infact[i] = q_pow(fact[i], MOD - 2, MOD);
    }
}

LL get(LL a, LL b) {
   
    if (a < b) return 0;
    LL ans = fact[a] % MOD * infact[b] % MOD * infact[a - b] % MOD;
    return ans;
}

LL lucas(LL a, LL b) {
   
    if (b == 0) return 1;
    return lucas(a / MOD, b / MOD) * get(a % MOD, b % MOD) % MOD;
}

void solve() {
   
    cin >> n >> l >> r;
    LL a = r - l + n + 1;
    LL b = r - l + 1;
    LL ans = lucas(a, b) - 1;
    ans = (ans % MOD + MOD) % MOD;
    cout << ans << '\n';
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    init();
    int T;
    cin >> T;

    while (T--) solve();

    return 0;
}