1. 程式人生 > >6333 Harvest of Apples (莫隊)

6333 Harvest of Apples (莫隊)

題目連結

題意:給你T組詢問,每組詢問有兩個值n,m,讓你輸出C(n,0)+C(n,1)+...+C(n,m-1)+C(n,m)的值。(1<=T,n,m<=1e5)

由於T的值太大,所以直接算會超時。

考慮莫隊演算法:

首先要有個預備知識:

S(n,m)=S(n,m-1)+C(n,m)=2S(n-1,m)-C(n-1,m),S(n,m)=\sum_{i=0}^{m}C(n,i)

這樣,知道S(n,m-1)的值,就能在O(1)的時間算出S(n,m)的值了。可以按照m的大小分塊,把m,n作為左右下標,來回跳就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int SQRTN=sqrt(N)+10;
const ll mod=1e9+7.5;
int in[N];
ll ans[N],fact[N],inv[N],invfact[N];
struct query
{
    int i;
    ll n,m;
    bool operator<(const query& b)
    {
        return in[m]==in[b.m]?(in[m]&1?n>b.n:n<b.n):m<b.m;
    }
} qr[N];

void init()
{
    inv[1]=fact[0]=invfact[0]=1;
    for(int i=2; i<N; ++i)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1; i<N; ++i)
    {
        fact[i]=fact[i-1]*i%mod;
        invfact[i]=invfact[i-1]*inv[i]%mod;
    }
}

ll C(ll n,ll m)
{
    return n<m?0:fact[n]*invfact[m]%mod*invfact[n-m]%mod;
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    for(int i=0; i<T; ++i)
    {
        scanf("%lld%lld",&qr[i].n,&qr[i].m);
        qr[i].i=i;
        in[i]=i/SQRTN;
    }
    sort(qr,qr+T);
    ll m=0,n=1,sum=1;
    for(int i=0; i<T; ++i)
    {
        while(m<qr[i].m)++m,sum=(sum+C(n,m))%mod;
        while(m>qr[i].m)sum=(sum-C(n,m))%mod,--m;
        while(n<qr[i].n)++n,sum=(sum*2-C(n-1,m))%mod;
        while(n>qr[i].n)sum=(sum+C(n-1,m))*inv[2]%mod,--n;
        ans[qr[i].i]=(sum+mod)%mod;
    }
    for(int i=0; i<T; ++i)printf("%lld\n",ans[i]);
    return 0;
}