AcWing 1312. 序列统计
\(AcWing\) \(1312\). 序列统计
一、题目描述
给定三个整数 \(N,L,R\),统计长度在 \(1\) 到 \(N\) 之间,元素大小都在 \(L\) 到 \(R\) 之间的 单调不降序列 的数量。
输出答案对 \(10^6+3\) 取模的结果。
输入格式
输入第一行包含一个整数 \(T\),表示数据组数。
第二到第 \(T+1\) 行每行包含三个整数 \(N,L,R\)。
输出格式
输出包含 \(T\) 行,每行有一个数字,表示你所求出的答案对 \(10^6+3\) 取模的结果。
数据范围
\(0≤N,L,R≤10^9,1≤T≤100\),输入数据保证 \(L≤R\)。
输入样例:
2
1 4 5
2 4 5
输出样例:
2
5
样例解释
对于第一组输入,满足条件的两个序列为 \(\{4\},\{5\}\)。
对于第二组输入,满足条件的五个序列为\(\{4\},\{5\},\{4,4\},\{5,5\},\{4,5\}\)
二、算法分析
1、长度是 \(k\) 的序列
枚举序列长度\(k\),则对于选出来的元素一定满足\(L<=a_1<=a_2<=…<=a_k<=R\) ,这样才算是题目要求的单调不降序列
我们更希望可以将 \(a_1<=a_2<=…<=a_k\) 的形式转化为 \(b_1<b_2<…<b_k\)的形式,因为后者可以通过隔板法更容易解决
常用的转换方法:将差值映射变大,令
\(\displaystyle b_1=a_1\)
\(\displaystyle b_2=a_2+1\)
\(\displaystyle b_3=a_3+2\)
...
\(\displaystyle b_k=a_k+k-1\)
则原不等式
转换成
每找到一个 \(a_i\) 都能对应映射成一个 \(b_i\) ,同时每找到一个 \(b_i\) 都能对应映射成一个 \(a_i\),这样构建出来的不等组与原不等式是等价的
因此序列长度是 \(k\) 的方案是 $$\large C_{R+k−1−L+1}k=C_{R−L+k}k$$
但是,由于选择的元素数量\(k\)不确定,取值范围还很大,是 \(10^9\)。暴力枚举\(k\)肯定不行,需要继续想办法处理:
2、计算出长度是\(1,2,3 … N\) 的序列总方案数
由于序列长度是 \(k\) 的方案是 \(C_{R−L+k}^k\),令 \(R−L=m\),则 \(k\) 取 \(1,2....N\) 时的 总方案数 是
\(\large \displaystyle =C_{m+1}^1+C_{m+2}^2+C_{m+3}^3+...+C_{m+n}^n\)
下面是一个 经典的变形技巧 ,利用公式:
\(\large \displaystyle C_{a}^b=C_{a-1}^{b}+C_{a-1}^{b-1} \Rightarrow C_{m+1}^{0}+C_{m+1}^{1}=C_{m+2}^{1}\)
然后形成多米诺骨牌,顺次形成递推关系,一路向前~
\(\large =C_{m+1}^0 +C_{m+1}^1+C_{m+2}^2+C_{m+3}^3+...+C_{m+n}^n - C_{m+1}^0 \\ =C_{m+2}^1+C_{m+2}^2+C_{m+3}^3+...+C_{m+n}^n - C_{m+1}^0 \\ ... \\ =C_{m+n+1}^n-C_{m+1}^0 \\ =C_{m+n-1}^n-1 \)
题目给定 \(P = 10^6+3, N = 10^9\),因此只能用卢卡斯定理解决
时间复杂度 \(O(Plog_pN)\)
\(Lucas\)定理的时间复杂度是\(O(Plog_pN)\)
三、实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int p = 1000003;
/**
* 功能:快速幂模板
* @param a
* @param k
* @param p
* @return
*/
int qmi(int a, int k, int p) {
int res = 1;
while (k) {
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
/**
* 功能:组合数模板
* @param a 在a个数中
* @param b 取b个数
* @param p 一个质数,用来取模
* @return 多少种办法
*/
int C(int a, int b, int p) {
if (a < b) return 0;
int down = 1, up = 1;
for (int i = a, j = 1; j <= b; i--, j++) {
up = (LL)up * i % p;
down = (LL)down * j % p;
}
return (LL)up * qmi(down, p - 2, p) % p;
}
/**
* 功能:Lucas公式模板
* @param a
* @param b
* @param p
* @return
*/
int lucas(LL a, LL b, int p) {
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p; //套用公式,还有个递归
}
int main() {
int T;
cin >> T;
while (T--) {
int n, l, r;
cin >> n >> l >> r;
cout << (lucas(r - l + n + 1, r - l + 1, p) - 1 + p) % p << endl;
}
return 0;
}

浙公网安备 33010602011771号