杭电多校第四次 Problem B. Harvest of Apples(莫队

思路:

S[i][j]=S[i-1][j]+S[i-1][j-1](递推到每一项和求和都满足这个公式)
S[i-1][j-1]=S[i-1][j]-C[i-1][j]
所以S[i][j]=2*S[i-1][j]-C[i-1][j]
同理可推出余下的公式

S(l,r)=S(l,r-1)+C(l,r)
S(l,r)=2*S(l-1,r)-C(l-1,r);
S(l,r)=S(l,r+1)-C(l,r+1)
S(l,r)=(S(l+1,r)-C(l,r))/2;
先用组合数模板预处理出来所有的组合数
然后就可以用莫队来写了

排序的时候
block是根号1e5 这样对询问的左端点进行分块,那么总共会分成1e5/block 大概=317块,这样每一块中:左端点都比较接近,而右端点从1到1e5,忽略左端点的移动处理完这一块大概需要移动1e5次,总共有317块,所以总的复杂度就是n√n

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=1e5+5;
const int mod=1e9+7;
ll inv[maxn],fac[maxn],ans[maxn],pos[maxn];
ll qpow(ll a,int b)
{
    ll ans=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans;
}
void pre()
{
    fac[0]=fac[1]=1;
    for(int i=2;i<maxn;++i) fac[i]=i*fac[i-1]%mod;
    inv[maxn-1]=qpow(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll Comb(int n,int k)
{
    if (k < 0 || k > n) return 0;
    return fac[n]*inv[k]%mod *inv[n-k]%mod;
}
struct node
{
    int l,r,id;
}p[maxn];
int cmp(node a,node b)
{
    if(pos[a.l]!=pos[b.l])
        return a.l<b.l;
    return a.r<b.r;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    pre();
    int t;
    scanf("%d",&t);
    int block=(int)sqrt(1.0*maxn);
    for(int i=1;i<=t;i++)
    {
        scanf("%d%d",&p[i].l,&p[i].r);
        pos[i]=i/block;
        p[i].id=i;
    }
    sort(p+1,p+1+t,cmp);
    ll res=2;
    int curL=1,curR=1;
    for(int i=1;i<=t;++i)
    {
        while(curL<p[i].l)
        {
            curL++;
            res = (2*res%mod - Comb(curL-1,curR)+mod)%mod;
        }
        while(curR<p[i].r)
        {
            curR++;
            res = (res+Comb(curL,curR))%mod;
        }
        while(curL>p[i].l)
        {
            res = (res+Comb(curL-1,curR))%mod *inv[2] %mod;
            curL--;
        }
        while(curR>p[i].r)
        {
            res = (res-Comb(curL,curR)+mod)%mod;
            curR--;
        }
        ans[p[i].id] = res;
    }
    for(int i=1;i<=t;i++)
        printf("%lld\n",ans[i]);
    return 0;
}
posted @ 2018-08-03 17:32  ffgcc  阅读(65)  评论(0编辑  收藏  举报