题目大意
求 f(n,m)=∑mi=0Cin f ( n , m ) = ∑ i = 0 m C n i , 多组数据。
解题分析
上莫队。
如果已经求出了 f(n,m) f ( n , m ) ,那么如何求出 f(n+1,m) f ( n + 1 , m ) 和 f(n,m+1) f ( n , m + 1 ) 呢?
f(n,m+1)=f(n,m)+Cm+1n f ( n , m + 1 ) = f ( n , m ) + C n m + 1
f(n+1,m)=∑mi=0Cin+1=∑mi=1(Cin+Ci−1n)+1=f(n,m)+f(n,m−1)=2∗f(n,m)−Cnm f ( n + 1 , m ) = ∑ i = 0 m C n + 1 i = ∑ i = 1 m ( C n i + C n i − 1 ) + 1 = f ( n , m ) + f ( n , m − 1 ) = 2 ∗ f ( n , m ) − C m n
所以可以 O(1) O ( 1 ) 转移,这样就可以用莫队了。
示例程序
#include<cmath>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int tt=1000000007,invt=(tt+1)>>1,maxn=100005;
int S,q,h[maxn],ans[maxn];
LL num,fac[maxn],inv[maxn];
struct data{
int L,R,id;
data (int L=0,int R=0,int id=0):L(L),R(R),id(id){}
bool operator < (const data b)const{
if (h[L]==h[b.L]) return R<b.R;
return L<b.L;
}
}a[100005];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
LL ksm(LL x,int y){
LL sum=1,w=x;
for (;y;y>>=1,w=(w*w)%tt) if (y&1) sum=(sum*w)%tt;
return sum%tt;
}
void blocker(int n){
S=sqrt(n);
for (int i=1;i<=n;i++) h[i]=(i-1)/S+1;
}
LL C(int n,int m){
if (n==m) return 1;
return (fac[n]*inv[m]%tt)*inv[n-m]%tt;
}
int main()
{
freopen("apple.in","r",stdin);
freopen("apple.out","w",stdout);
readi(q); blocker(q);
for (int i=1,x,y;i<=q;i++) {readi(x); readi(y); a[i]=data(y,x,i);}
num=1; sort(a+1,a+q+1);
fac[0]=1; for (int i=1;i<=1e5;i++) fac[i]=(fac[i-1]*i)%tt;
for (int i=0;i<=1e5;i++) inv[i]=ksm(fac[i],tt-2);
for (int i=1,L=0,R=0;i<=q;i++){
while (R<a[i].R) num=((num<<1)-C(R++,L)+tt)%tt;
while (R>a[i].R) num=(num+C(--R,L))%tt*invt%tt;
while (L<a[i].L) num=(num+C(R,++L))%tt;
while (L>a[i].L) num=(num-C(R,L--)+tt)%tt;
ans[a[i].id]=num;
}
for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
return 0;
}