【AT987】高橋君

题目

成爷爷一眼秒,\(tql!!!\)

多组询问,求

\[\sum_{i=0}^kC_{n}^i \]

发现\(k<=n\)啊,于是我们可以把一组询问抽象成一个区间\([k,n]\)

左指针的移动非常好解决,就是加一下\(C_n^k\)减一下\(C_n^k\)就好了

考虑一下右指针的移动,就是\(n+1\)或者\(n-1\)

如果\(n+1\),就是从\(\sum_{i=0}^kC_n^i\)变成了\(\sum_{i=0}^kC_{n+1}^i\)

我们利用组合数的小学生求法,拆开我们的柿子

\[\sum_{i=0}^kC_{n+1}^i=\sum_{i=0}^kC_{n}^i+C_{n}^{i-1}=2\times \sum_{i=0}^kC_{n}^i-C_n^k \]

如果是\(n-1\),就是求

\[\sum_{i=0}^kC_{n-1}^i=\sum_{i=0}^kC_{n}^i-C_{n-1}^{i-1} \]

也就是

\[2\times \sum_{i=0}^kC_{n-1}^i-C_{n-1}^k=\sum_{i=0}^kC_{n}^i \]

发现我们要求的东西都能从\(\sum_{i=0}^kC_n^i\)\(O(1)\)推过去

于是莫队就没了

成爷爷奇偶性排序\(wa\)了,这告诉我们拒绝玄学

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=1e5+5;
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const LL mod=1e9+7;
struct Ask{
	int l,r,rk;
}q[maxn];
LL fac[maxn],inv[maxn],I2,ans;
int Ans[maxn];
int n,m,sz,L,R;
inline int cmp(Ask A,Ask B) {
	if(A.l/sz==B.l/sz) return A.r<B.r;
	return A.l<B.l;
}
inline LL ksm(LL a,int b) {
	LL S=1;
	while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}
	return S;
}
inline LL C(int n,int m) {
	if(n<m) return 0;
	return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
inline void add_(int x) {ans+=C(R,x);ans%=mod;}
inline void del_(int x) {ans-=C(R,x);ans=(ans+mod)%mod;}
inline void add(int x) {
	ans=(ans*2ll)%mod;
	ans=(ans-C(x-1,L)+mod)%mod;
}
inline void del(int x) {
	ans=(ans+C(x-1,L))%mod;
	ans=(ans*I2)%mod;
}
int main() {
	m=read();
	for(re int i=1;i<=m;i++) 
		q[i].r=read(),q[i].l=read(),q[i].rk=i,n=max(n,q[i].r);
	fac[0]=1;
	for(re int i=1;i<=n;i++) 
		fac[i]=(fac[i-1]*(LL)i)%mod;
	inv[n]=ksm(fac[n],mod-2);
	for(re int i=n-1;i>=0;--i) 
		inv[i]=(inv[i+1]*(LL)(i+1))%mod;
	sz=std::sqrt(n);
	I2=ksm(2ll,mod-2);
	L=1,R=1;ans=2;
	std::sort(q+1,q+m+1,cmp);
	for(re int i=1;i<=m;i++) {
		while(R<q[i].r) add(++R);
		while(L>q[i].l) del_(L--);
		while(L<q[i].l) add_(++L);
		while(R>q[i].r) del(R--);
		Ans[q[i].rk]=ans;
	}
	for(re int i=1;i<=m;i++) printf("%d\n",Ans[i]);
	return 0;
}
posted @ 2019-03-29 18:58  asuldb  阅读(250)  评论(0编辑  收藏  举报