LibreOJ10235. 序列统计

https://loj.ac/p/10235

题目描述

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

输入格式

输入第一行包含一个整数 T,表示数据组数。

第二到第 T+1 行每行包含三个整数 N,LRN,LR 的意义如题所述。

输出格式

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

样例

输入

2
1 4 5
2 4 5

输出

2
5

对于第一组输入,满足条件的两个序列为 4,5

数据范围与提示

对于全部输入,1N,L,R109,1T100,输入数据保证 LR

题解

长度为 N,令 L=1

我们先从长度为 N 的单调不减序列 a1,a2,,aN 入手,其中 ai[1,R].

单调不减不好处理,我们令 bi=ai+(i1),即可得到一个单调增序列 b1,b2,,bN,其中 bi[1,R+(N1)].

原序列与变换后的序列能够保证一一对应,并且若变换后的序列满足单调增,原序列一定单调不减。

借助新序列,我们容易得出这种情况的数量为:CR+N1N

长度为 N

我们将上面的结论推广,计算长度为 N 的单调不减序列 a1,a2,,aN 的情况数,其中 ai[L,R].

我们令 ci=aiL+1,即可得到一个新的单调不减序列 c1,c2,,cN,其中 ci[1,RL+1],我们就可以再套用上面的结论。

这种情况的数量为:CRL+NN

长度为 1,2,,N 的总数

最后我们需要将所有情况加到一起,即:

n=1NCRL+nn

直接求和肯定要超时,尝试进行变形:

n=1NCRL+nn=n=1NCRL+nRL=n=1NCRL+nRL+CRL+1RL+11=n=2NCRL+nRL+CRL+1RL+CRL+1RL+11=n=2NCRL+nRL+CRL+2RL+11=n=3NCRL+nRL+CRL+2RL+CRL+2RL+11=n=3NCRL+nRL+CRL+3RL+11=CRL+N+1RL+11

最后结果仅为一个组合数。数据规模 109,对质数 106+3 取模,因此考虑使用卢卡斯定理求解该组合数。

代码

#include <bits/stdc++.h>

using namespace std;

const int MOD = 1e6 + 3;
long long fact[MOD + 10];

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

long long fast_pow(long long a, long long b, long long p)
{
    b %= p;
    long long ans = 1;
    while (b)
    {
        if (b % 2)
            ans = a * ans % p;
        a = a * a % p;
        b /= 2;
    }
    return ans;
}

inline long long inv(long long x, long long p)
{
    return fast_pow(x, p - 2, p);
}

long long comb(long long a, long long b, long long p)
{
    if (b > a)
        return 0;
    if (a < p && b < p)
        return fact[a] * inv(fact[b], p) % p * inv(fact[a - b], p) % p;
    return comb(a % p, b % p, p) * comb(a / p, b / p, p) % p;
}

int main()
{
    int n;
    cin >> n;
    init();
    while (n--)
    {
        long long N, L, R;
        cin >> N >> L >> R;
        cout << ((comb(N + (R - L + 1), R - L + 1, MOD) - 1) % MOD + MOD) % MOD << endl;
    }
    return 0;
}