HDU 6333 Problem B. Harvest of Apples(莫队离线)

Problem B. Harvest of Apples(莫队离线)

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1792 Accepted Submission(s): 699

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≤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

题意

  求 i = 0 m C(n,i)。

解题思路

  开始拿到这个题的时候还有些窃喜,诶,组合数求和,逆元搞一搞就行了,多捞哦!然后仔细一看数据范围,O(n^2)算法复杂度必超,尝试性的挑战了一下后台样例,果断TLE。然后我TM就找规律去了,woc杨辉三角,有点搞头,然后就没有然后了。。

  以前没有学过莫队算法,这真的是一种神奇的暴力解题方式。因为这题没有涉及到数据更新,所以我们可以把查询离线,然后分块。又因为(我们这里令 i = 0 m C(n,i)=S(n,m))

S(n+1,m)=2*S(n,m)-C(n,m)

S(n-1,m)=S(n,m)+C(n-1,m)

S(n,m+1)=S(n,m)+C(n,m+1)

S(n,m-1)=S(n,m)-C(n,m)

  PS:如果我们知道区间[L,R],就能在比较短的时间内求出[L−1,R],[L+1,R],[L,R−1],[L,R+1]的话,那就可以用莫队算法了。具体看代码吧。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+50;
const int mod = 1e9+7;

long long inv[maxn],fac[maxn];
long long quickpow(long long a, long long b)
{
    long long ret = 1;
    a %= mod;
    while(b)
    {
        if (b & 1) ret = (ret * a) % mod;
        b >>= 1;
        a = (a * a) % mod;
    }
    return ret;
}
void init()
{
    fac[0]=inv[0]=1;
    for(int i=1; i<maxn; i++)
    {
        fac[i]=(fac[i-1]*i)%mod;  //得到阶乘
        inv[i]=quickpow(fac[i],mod-2);  //得到阶乘的逆元
    }
}

int pos[maxn];//块
struct node
{
    int n,m,id;
} p[maxn];

int cmp(node a,node b)//让相邻两个操作的操作次数尽可能的小
{
    if(pos[a.n]==pos[b.n]) return a.m<b.m;
    return pos[a.n]<pos[b.n];
}
int n,m;
long long ans,res[maxn];

long long getnumber(int n,int m)
{
    if(n<m) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void addn(int n,int m)  /*S(n+1,m)=2*S(n,m)-C(n,m)*/
{
    ans=(2*ans%mod-getnumber(n,m)+mod)%mod;  //不加mod取模会错
}
void addm(int n,int m)  /*S(n-1,m)=S(n,m)+C(n-1,m)*/
{
    ans=(ans+getnumber(n,m+1))%mod;
}
void subn(int n,int m)  /*S(n,m+1)=S(n,m)+C(n,m+1)*/
{
    ans=(ans+getnumber(n-1,m))*inv[2]%mod;
}
void subm(int n,int m)  /*S(n,m-1)=S(n,m)-C(n,m)*/
{
    ans=(ans-getnumber(n,m)+mod)%mod;    //ts
}

int main()
{
#ifdef DEBUG
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif // DEBUG
    init();
    int t,block=(int)sqrt(1.0*maxn);
    scanf("%d",&t);
    for(int i=1; i<=t; i++) scanf("%d%d",&p[i].n,&p[i].m),p[i].id=i,pos[i]=i/block;
    sort(p+1,p+1+t,cmp);
    n=1,m=0,ans=1;
    for(int i=1; i<=t; i++)
    {
        while(n<p[i].n) addn(n++,m);
        while(n>p[i].n) subn(n--,m);
        while(m<p[i].m) addm(n,m++);
        while(m>p[i].m) subm(n,m--);
        res[p[i].id]=ans;
    }
    for(int i=1; i<=t; i++) printf("%lld\n",res[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36258516/article/details/81363560