[BZOJ4403]序列统计 题解

[BZOJ4403]序列统计 题解

题目地址:BZOJ:Problem 4403. — 序列统计

题目描述

给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对10^6+3取模的结果。

输入输出格式

输入格式:
输入第一行包含一个整数T,表示数据组数。
第2到第T+1行每行包含三个整数N、L和R,N、L和R的意义如题所述。
1≤N,L,R≤10^9,1≤T≤100,输入数据保证L≤R。

输出格式:
输出包含T行,每行有一个数字,表示你所求出的答案对10^6+3取模的结果。

输入输出样例

输入样例#1:

2
1 4 5
2 4 5

输出样例#1:

2
5

题解

本题需要的数学姿势:卢卡斯定理原理及应用 | KSkun’s Blog
首先,本题只需选出数而不在意它们的顺序,我们考虑转化成n个小球放入m=r-l+1个盒子里这个问题,使用插板法,得到m个数组成长度为n的不下降序列的方案数为\mathrm{C}_{n+m-1}^{m-1},也就是说,我们想求的答案是\sum_{i=1}^n \mathrm{C}_{i+m-1}^{m-1}
我们知道有公式\mathrm{C}_i^j = \mathrm{C}_{i-1}^j + \mathrm{C}_{i-1}^{j-1},我们来利用这个公式合并每一项。
\begin{aligned} & \mathrm{C}_{1+m-1}^{m-1} + \mathrm{C}_{2+m-1}^{m-1} + \cdots + \mathrm{C}_{n+m-1}^{m-1} \\ =& \mathrm{C}_{1+m-1}^m + \mathrm{C}_{1+m-1}^{m-1} + \mathrm{C}_{2+m-1}^{m-1} + \cdots + \mathrm{C}_{n+m-1}^{m-1} - 1 \\ =& \mathrm{C}_{1+m}^m + \mathrm{C}_{1+m}^{m-1} + \cdots + \mathrm{C}_{n+m-1}^{m-1} - 1 \\ =& \mathrm{C}_{2+m}^m + \mathrm{C}_{2+m}^{m-1} + \cdots + \mathrm{C}_{n+m-1}^{m-1} - 1 \\ =& \cdots \\ =& \mathrm{C}_{n+m}^m - 1 \end{aligned}
这个可以利用Lucas定理解决。

代码

// Code by KSkun, 2018/4
#include <cstdio>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 1000005, MO = 1000003;

LL T, n, l, r, mul[MAXN], inv[MAXN];

inline LL C(LL n, LL m) {
    if(m > n) return 0;
    return mul[n] * inv[n - m] % MO * inv[m] % MO;
}

inline LL lucas(LL n, LL m) {
    if(!m) return 1;
    return lucas(n % MO, m % MO) * lucas(n / MO, m / MO) % MO;
}

inline void cal() {
    mul[0] = mul[1] = inv[0] = inv[1] = 1;
    for(int i = 2; i < MO; i++) {
        inv[i] = (-(MO / i) * inv[MO % i] % MO + MO) % MO;
    }
    for(int i = 2; i < MO; i++) {
        mul[i] = mul[i - 1] * i % MO;
        inv[i] = inv[i - 1] * inv[i] % MO;
    }
}

int main() {
    T = readint();
    cal();
    while(T--) {
        n = readint(); l = readint(); r = readint();
        LL m = r - l + 1;
        printf("%lld\n", (lucas(n + m, m) - 1 + MO) % MO);
    }
    return 0;
}


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据