题意:求出C(n,0)~C(n,m)的和,mod 1e9+7 。
分析:题目给的数据范围1<=n,m<=1e5,1<=T<=1e5,直接求出C(n,i)然后累加起来显然复杂度不行,在官方的题解中给出了如下的公式。
虽然在比赛中找出了这两个东西,但是看过的人那么多,一味的以为有直接用公式算出来的方法,所以一直在推公式,思维太局限,没有想到莫队。预处理阶乘和逆元,在双指针移动的时候能够O(1)的求出C(i,j);废话不多说,上代码。
#include <bits/stdc++.h>
#define mst(a,b) memset(a,b,sizeof(a))
#define ALL(x) x.begin(),x.end()
#define pii pair<int,int>
#define eps 1e-8
inline int lowbit(int x){ return x & -x; }
const int N = 1e5+10;
const long long mod = (long long) 1e9 + 7;
const int INF = 0x3f3f3f3f;
const long long LINF = (1LL << 62);
typedef long long LL;
typedef unsigned long long ULL;
const double PI = acos(-1.0);
using namespace std;
LL C[N],inv[N],ans[N];
int bl[N];
struct Q{
int n, m, id, No;
bool operator < (const Q &t) const{
if(id != t.id) return id < t.id; //对块排序,相同的块就按右区间小的排
return m < t.m;
}
}Q[N];
LL q_pow(LL base, LL b){
LL res = 1;
while(b){
if(b&1) res = res * base % mod;
base = base * base % mod;
b >>= 1;
}
return res;
}
void init(){ //预处理阶乘和逆元
C[0] = C[1] = 1;
for(int i = 2; i <= 1e5; i++) C[i] = C[i - 1] * i % mod;
inv[(int)1e5] = q_pow(C[(int)1e5], mod - 2);
for(int i = 1e5 - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
inline LL get_C(int n, int m){
return C[n] * inv[m] % mod * inv[n - m] % mod;
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
#else
// freopen("caravan.in","r",stdin);
// freopen("caravan.out","w",stdout);
#endif
init();
LL inv2 = q_pow(2, mod - 2);
int blo = sqrt(1e5);
for(int i = 1; i <= 1e5; i++) bl[i] = (i - 1) / blo + 1; //预处理每个数所在的块的编号
int T; scanf("%d",&T);
int n, m;
for(int i = 1; i <= T; i++){
scanf("%d%d",&Q[i].n,&Q[i].m);
Q[i].No = i;
Q[i].id = bl[Q[i].n];
}
sort(Q + 1, Q + 1 + T);
int l = 0, r = 0;
LL sum = 1;
for(int i = 1; i <= T; i++){ //然后就是愉快的左右指针移动求答案了,下面就是公式所对应的东西。
while(l < Q[i].n) sum = (sum + sum - get_C(l, r) + mod) % mod, l++;
while(l > Q[i].n) sum = (sum + get_C(l - 1, r)) * inv2 % mod, l--;
while(r < Q[i].m) sum = (sum + get_C(l, r + 1)) % mod, r++;
while(r > Q[i].m) sum = (sum - get_C(l, r) + mod) % mod, r--;
ans[Q[i].No] = sum;
}
for(int i = 1; i <= T; i++) printf("%I64d\n",ans[i]);
return 0;
}