杭电多校第四次 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;
}