HDU 6333 Problem B.Harvest of Apples 莫队+组合数学

Problem Description

There are n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most m apples.

Input

The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤105).

Output

For each test case, print an integer representing the number of ways modulo 109+7.

Sample Input

2
5 2
1000 500

Sample Output

16
924129523

Source

2018 Multi-University Training Contest 4

Solution

莫队

可以使用莫队离线处理1e5个询问,将将n^2的时间复杂度降到n*sqrt(n),从整个儿的大无序区间到sqrt(n)个对外有序对内无序的小区间;
鄙人由此题始知一二,仍甚不熟悉,还需多学多练。

组合数学

公式推导如下图
这里写图片描述

Code

#include <bits/stdc++.h>

#define ll long long
using namespace std;
const ll mod = 1000000007;
const int N = 100001;
int T, x, curL, curR;
int pos[N];
ll res, ans[N], fac[N], inv[N];

struct data {
    int L, R, id;

    bool operator<(const data &b) const {
        if (pos[L] == pos[b.L]) return R < b.R;
        return L < b.L;
    }
} q[N];

ll fun(ll a, ll k) {
    ll res = 1;
    while (k) {
        if (k & 1) res = res * a % mod;
        a = a * a % mod;
        k >>= 1;
    }
    return res;
}

ll Comb(int n, int m) {
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

inline void addN(int l, int r) {
    res = (res + res - Comb(l, r) + mod) % mod;
}

inline void delN(int l, int r) {
    res = (res + Comb(l - 1, r)) * inv[2] % mod;
}

inline void addM(int l, int r) {
    res = (res + Comb(l, r + 1)) % mod;
}

inline void delM(int l, int r) {
    res = (res - Comb(l, r) + mod) % mod;
}

int main() {
    //freopen("../in", "r", stdin);

    fac[0] = inv[0] = 1;
    for (int i = 1; i < N; ++i) fac[i] = fac[i - 1] * i % mod;
    inv[N - 1] = fun(fac[N - 1], mod - 2);
    for (int i = N - 2; i > 0; --i) inv[i] = inv[i + 1] * (i + 1) % mod;
    x = sqrt(N);

    scanf("%d", &T);
    for (int i = 0; i < T; ++i) {
        q[i].id = i;
        pos[i] = i / x;
        scanf("%d%d", &q[i].L, &q[i].R);
    }

    sort(q, q + T);
    res = 2, curL = 1, curR = 1;
    for (int i = 0; i < T; ++i) {
        while (curL < q[i].L) addN(curL++, curR);
        while (curL > q[i].L) delN(curL--, curR);
        while (curR < q[i].R) addM(curL, curR++);
        while (curR > q[i].R) delM(curL, curR--);
        ans[q[i].id] = res;
    }
    for (int i = 0; i < T; ++i) printf("%lld\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ACM2017/article/details/81383447