高橋君

模拟赛出了一道复合题,后半部分就是这道。

题目大意

给定 \(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;
}
posted @ 2023-10-04 20:21  -白简-  阅读(17)  评论(0编辑  收藏  举报