1. 程式人生 > >【HDU - 6333】Harvest of Apples

【HDU - 6333】Harvest of Apples

@Harvest of [email protected]


@題目描述 - [email protected]

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≤10^5) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤10^5).

Output
For each test case, print an integer representing the number of ways modulo 10^9+7.

Sample Input
2
5 2
1000 500
Sample Output


16
924129523

@大致題意@

T組詢問,每組詢問包含n, m。求:

i = 0 m C
n i

T,n,m <= 10^5

@分析@

這麼優美的式子居然沒有通項公式!
它!居然!沒有通項公式!!!
沒有通項公式的話……我們也只能考慮暴力一點的做法……

我們令 S n m = i = 0 m C n i
則有:

1 S n m + 1 = i = 0 m + 1 C n i = S n m + C n m + 1

反過來可知 S n m 1 = S n m C n m

2 S n + 1 m = i = 0 m C n + 1 i = C n + 1 0 + i = 1 m ( C n i + C n i 1 ) = S n m C n 0 + S n m 1 + C n + 1 0 = 2 S n m C n m

反過來可知 S n 1 m = S n m + C n 1 m 2

我們可以通過預處理階乘及逆元O(1)求出 C n m
那麼上面的式子就告訴我們,如果我們已知 S n m ,則可以O(1)求出 S n m + 1 , S n m 1 , S n + 1 m , S n 1 m

這個特徵其實就是莫隊演算法的特徵。儘管問題詢問的不是區間,但我們仍然可以使用莫隊演算法解決。

【碼一下 yhn 學長的莫隊總結】

具體的話,就是把n看成區間左端點,m看成區間右端點,其他的大致細節就是按照莫隊演算法來。

@程式碼@

【學過不會用系列】
如果有什麼問題可以參考程式碼細節,或也可以留言在下面詢問。我會盡力解答問題的OuO

#include<cstdio>
#include<algorithm>
using namespace std;
const int BLOSIZ = 320;
const int MAXN = 100000;
const int MOD = int(1E9) + 7;
struct node{
    int le, ri;
    int id;
}qry[MAXN + 5];
bool operator < (node a, node b) {
    if( a.le / BLOSIZ == b.le / BLOSIZ )
        return a.ri < b.ri;
    else return a.le < b.le;
}
int fact[MAXN + 5], inv[MAXN + 5];
int pow_mod(int b, int p) {
    int ret = 1;
    while( p ) {
        if( p & 1 )
            ret = 1LL * ret * b % MOD;
        b = 1LL * b * b % MOD;
        p >>= 1;
    }
    return ret;
}
void Init() {
    fact[0] = 1;
    for(int i=1;i<=MAXN;i++)
        fact[i] = 1LL * fact[i-1] * i % MOD;
    inv[MAXN] = pow_mod(fact[MAXN], MOD-2);
    for(int i=MAXN-1;i>=0;i--)
        inv[i] = 1LL * inv[i+1] * (i+1) % MOD;
}
int Comb(int n, int m) {
    if( n < m ) return 0;
    else return 1LL * fact[n] * inv[m] % MOD * inv[n-m] % MOD;
}
int ans[MAXN + 5];
int le, ri, sum;
int main() {
    Init(); int T;
    scanf("%d", &T);
    for(int i=1;i<=T;i++) {
        scanf("%d%d", &qry[i].le, &qry[i].ri);
        qry[i].id = i;
    }
    sort(qry+1, qry+T+1);
    le = ri = 0, sum = 1;
    for(int i=1;i<=T;i++) {
        while( ri < qry[i].ri ) {
            sum = (sum + Comb(le, ri+1)) % MOD;
            ri++;
        }
        while( ri > qry[i].ri ) {
            sum = (sum - Comb(le, ri)) % MOD;
            ri--;
        }
        while( le < qry[i].le ) {
            sum = (2LL*sum - Comb(le, ri)) % MOD;
            le++;
        }
        while( le > qry[i].le ) {
            sum = 1LL*(sum + Comb(le-1, ri))*inv[2] % MOD;
            le--;
        }
        ans[qry[i].id] = sum;
    }
    for(int i=1;i<=T;i++)
        printf("%d\n", (ans[i] + MOD) % MOD);
}

@[email protected]

就是這樣,新的一天裡,也請多多關照哦(ノω<。)ノ))☆.。~