【HDU - 6333】Harvest of Apples

版权声明:本文为博主原创文章……懂吗?要尊重别人的劳动成果呐 https://blog.csdn.net/Tiw_Air_Op1721/article/details/82377422

@Harvest of Apples@


@题目描述 - English@

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);
}

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

猜你喜欢

转载自blog.csdn.net/Tiw_Air_Op1721/article/details/82377422