Count Sequences题解
题目
题解
真的是, 一道简单题想了半天, 还是太菜了qwq
直接考虑整个序列的天填发显然是很复杂的, 所以考虑转变思路。
对于一个数列, 因为需要其单调, 所以可以将其拆分成
\[a_1个L, a_2个(L+1), a_3个(L+2), ..., a_k个R
\]
那么, 这道题就变得简单了起来。
可能有人还是没有理解为什么, 其实上面这个转换就将问题变成了将 \(n\) 个元素分配给 \(L\) ~ \(R\) 。
这就是经典的小球放盒问题, 所以我才说这道题就结束了。
但是, 注意到这里的 \(n\) , \(m\) 是在 \(1 \leq n, m \leq 10^9\) 所以我们会用到 Lucas定理 , 及
\[若 {\large p} 为质数, 设 {\large n = \overline{n_1n_2n_3...n_k}}, {\large m = \overline{m_1m_2m_3...m_k}}, 则有{\large \dbinom{n}{b}\equiv \Pi_{i = 1}^{k}\dbinom{n_i}{m_i} (mod\ p)}
\]
这样就可以完美的解决这个问题了。
接着, 我们就可以愉快地写代码了。
为啥连样例都过不了???
样例解释:
test #2: [4], [5], [4, 4], [4, 5] and [5, 5] are the five sequences.
啥东西, 原来要求的是序列长度小于等于 \(n\) 的(不包括空集).
阿哲。。。
我们将式子改一改不就完了吗?
开始的式子推出来应该是:
\[\dbinom{n + (r - l + 1) - 1}{(r - l + 1) - 1}
\]
既然是小于等于, 那就直接把所有长度加起来就好了:
\[={\large \sum \limits_{i = 1}^{n}\dbinom{i + (r - l + 1) - 1}{(r - l + 1) - 1}}
\]
没有 \(i = 0\) 以后不好求, 所以考虑先加回去再减掉:
\[={\large {\Bigg (}\sum \limits_{i = 0}^{n}\dbinom{i + (r - l + 1) - 1}{(r - l + 1) - 1}{\Bigg )} - 1}
\]
用一个变上指标求和公式搞定一切:
\[={\large \dbinom{n + (r - l + 1)}{r - l + 1} - 1}
\]
最终, 我们终于把这个SB神奇的式子给化成了一个只含一个组合数的式子了, 我们就可以重新打代码了。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 1000003
#define INF 1000003
long long fac[MAXN + 5];
long long inv_fac[MAXN + 5];
long long Pow (long long a, int b) {
long long ans = 1;
while (b) {
if (b & 1) {
ans *= a;
ans %= INF;
}
a *= a;
a %= INF;
b >>= 1;
}
return ans;
}
long long C(int a, int b) {
if (b < 0) {
return 0;
}
else if (a < b) {
return 0;
}
return fac[a] * inv_fac[b] % INF * inv_fac[a - b] % INF;
}
long long lucas (long long n, long long m) {
if (n < m) {
return 0;
}
else if (m == 0 || m == n) {
return 1;
}
return C(n % INF, m % INF) * lucas (n / INF, m / INF) % INF;
}
int main () {
fac[0] = 1;
for (int i = 1; i <= MAXN - 1; i ++) {
fac[i] = fac[i - 1] * i % INF;
}
inv_fac[MAXN - 1] = Pow (fac[MAXN - 1], INF - 2);
for (int i = MAXN - 1 - 1; i >= 0; i --) {
inv_fac[i] = inv_fac[i + 1] * (i + 1) % INF;
}
int t;
scanf ("%d", &t);
while (t --) {
int n;
long long l, r;
scanf ("%d %lld %lld", &n, &l, &r);
printf ("%lld\n", (lucas (n + (r - l + 1), (r - l + 1)) - 1 + INF) % INF);
}
}