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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章