高橋君
模拟赛出了一道复合题,后半部分就是这道。
题目大意
给定 \(T\) 个询问,对于每个询问,给出 \(n,k\),求出
\[\sum^{k}_{i=0}{n \choose i}
\]
答案对 \(10^9+7\) 取模。
思路
考虑 \(n\) 和 \(k\) 分别增加或减少 \(1\) 的情况。
以下变换运用了帕斯卡法则:
\[{n \choose k}={n - 1 \choose k}+{n - 1 \choose k - 1}
\]
考虑当 \(n\) 变为 \(n+1\) 时,
\[\begin{aligned}
& \ \ \ \ \ \sum^{k}_{i=0}{n+1 \choose i} \\
&= \sum^{k}_{i=0} \left( {n \choose i}+{n \choose i - 1} \right) \\
&= 2\sum^{k}_{i=0}{n \choose i} - {n \choose k}
\end{aligned}
\]
可以移项直接得到当 \(n\) 变为 \(n-1\) 的情况,
\[\begin{aligned}
\sum^{k}_{i=0}{n - 1 \choose i} = \dfrac{1}{2} \left( \sum^{k}_{i=0}{n \choose i} + {n \choose k} \right)
\end{aligned}
\]
当 \(k\) 变为 \(k +1\) 时,
\[\sum^{k+1}_{i=0}{n \choose i}=\sum^{k}_{i=0}{n \choose i}+{n \choose k + 1}
\]
当 \(k\) 变为 \(k-1\) 时,类似上面,
\[\sum^{k-1}_{i=0}{n \choose i}=\sum^{k}_{i=0}{n \choose i}-{n \choose k}
\]
可以发现,上面四个转移只需要单个组合数,在预处理阶乘和逆元的条件下可以做到 \(O(1)\) 求组合数,所以转移是 \(O(1)\) 的。
考虑莫队进行转移,时间复杂度 \(O(n \sqrt{n})\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 100500;
const int Mod = 1e9 + 7;
int n, m;
int a[N];
template <typename Type>
void Inc(Type &x, Type y) {
x += y;
if (x >= Mod)
x -= Mod;
return;
}
template <typename Type>
void Dec(Type &x, Type y) {
x = x - y;
if (x < 0)
x += Mod;
return;
}
template <typename Type>
Type Mul(Type x, Type y) {
return 1ll * x * y % Mod;
}
int Pow(int a, int b) {
a = a % Mod;
int res = 1;
while (b) {
if (b & 1)
res = 1ll * res * a % Mod;
b >>= 1;
a = 1ll * a * a % Mod;
}
return res;
}
int Inv(int a) {
return Pow(a, Mod - 2);
}
int fac[N], inv[N], Inv2 = Inv(2);
int C(int n, int m) {
if (n < m || m < 0)
return 0;
return 1ll * fac[n] * inv[m] % Mod * inv[n - m] % Mod;
}
struct Option {
int l, r, id, block;
} q[N];
int now = 1;
void Addl(int l, int r) {
now = Mul(now, 2);
Dec(now, C(l, r));
}
void Dell(int l, int r) {
Inc(now, C(l - 1, r));
now = Mul(now, Inv2);
}
void Addr(int l, int r) {
Inc(now, C(l, r + 1));
}
void Delr(int l, int r) {
Dec(now, C(l, r));
}
int ans[N],len;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> m;
len = sqrt(m);
for (int i = 1; i <= m; i++) {
int y, k;
cin >> y >> k;
q[i].l = y;
q[i].r = k;
q[i].id = i;
q[i].block = q[i].l / len;
}
int l = 0, r = 0;
fac[0] = 1;
for (int i = 1; i <= N - 500; i++)
fac[i] = Mul(fac[i - 1], i);
for (int i = 0; i <= N - 500; i++)
inv[i] = Inv(fac[i]);
sort(q + 1, q + m + 1,[](const Option &a, const Option &b) {
if(a.block == b.block)
return a.r < b.r;
return a.block < b.block;
});
for (int i = 1; i <= m; i++) {
while (l > q[i].l) {
Dell(l, r);
l--;
}
while (r < q[i].r) {
Addr(l, r);
r++;
}
while (l < q[i].l) {
Addl(l, r);
l++;
}
while (r > q[i].r) {
Delr(l, r);
r--;
}
ans[q[i].id] = now;
}
for (int i = 1; i <= m; i++)
cout << ans[i] << "\n";
return 0;
}