题目链接
题目大意
T T 组询问, 每组询问问.
数据范围
1≤T≤105
1
≤
T
≤
10
5
1≤m≤n≤105
1
≤
m
≤
n
≤
10
5
解题思路
定义
S(n,m)=∑mi=0Cin
S
(
n
,
m
)
=
∑
i
=
0
m
C
n
i
.
由杨辉三角的递推公式
Cmn=Cm−1n−1+Cmn−1
C
n
m
=
C
n
−
1
m
−
1
+
C
n
−
1
m
可以推导出
S(n,m)=2×S(n−1,m)−Cmn−1
S
(
n
,
m
)
=
2
×
S
(
n
−
1
,
m
)
−
C
n
−
1
m
这样我们就可以得到下面四个转移公式:
即使这样可以
O(1)
O
(
1
)
的转移, 但是最坏也是需要
O(n2)
O
(
n
2
)
的复杂度, 没办法实现。
这时候就可以把
m
m
和看成区间
l
l
和。 使用莫队算法处理一下。 以前没写过莫队, 正好趁这次机会学会了莫队算法。
使用莫队, 将
n
n
分成块, 按照
l
l
所在的块从小到大排序, 对于同一块内, 按照从小到大排序。
这样的话可以使复杂度降到
O(n∗n‾√)
O
(
n
∗
n
)
。
简单证明(现学现卖):
- 对于同一块内, l l 最多移动, r r 最多移动次,总共有 n‾√ n 块, 所以这种情况的复杂度为 O(n∗n‾√) O ( n ∗ n )
- 对不在同一块内的, l l 最多移动次, r r 还是移动次, 所以还是 O(n∗n‾√) O ( n ∗ n )
AC代码
/********************************************
*Author* :ZZZZone
*Created Time* : 日 8/ 5 14:48:44 2018
* Ended Time* : 日 8/ 5 15:24:14 2018
* 莫队算法
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
inline void OPEN(string s){
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
const int MAXN = 1e5;
const int Mod = 1e9 + 7;
LL fac[MAXN+5], rfac[MAXN+5], Ans[MAXN+5];
int blk[MAXN+5];
int n, Block;
struct Query{
int l, r, id;
bool operator < (const Query& tmp) const{
if(blk[l] == blk[tmp.l]) return r < tmp.r;
return blk[l] < blk[tmp.l];
}
}Q[MAXN+5];
LL fast_pow(LL x, LL y){
LL res = 1LL;
while(y != 0LL){
if(y & 1) res = (res * x) % Mod;
y >>= 1;
x = x * x % Mod;
}
return res;
}
inline LL Comb(LL N, LL M){
if(N<M)return 0LL; // ****** 一定不能忘 ****** //
return fac[N] * rfac[M] % Mod * rfac[N-M] % Mod;
}
void Init(){
fac[0] = 1LL;
for(int i = 1; i <= MAXN; i++) fac[i] = fac[i-1] * (LL)i % Mod;
for(int i = 0; i <= MAXN; i++){
rfac[i] = fast_pow(fac[i], Mod - 2LL);
blk[i] = i / Block;
}
for(int i = 1; i <= n; i++) scanf("%d %d", &Q[i].r, &Q[i].l), Q[i].id = i;
sort(Q + 1, Q + 1 + n);
}
int main()
{
scanf("%d", &n);
Block = sqrt(n);
Init();
int L = 1, R = 0;
LL ans = 1LL;
for(int i = 1; i <= n; i++){
while(L < Q[i].l){
L++;
ans = (ans + Comb(R, L)) % Mod;
}
while(L > Q[i].l){
ans = (ans - Comb(R, L) + Mod) % Mod;
L--;
}
while(R < Q[i].r){
ans = (2LL * ans % Mod - Comb(R, L) + Mod) % Mod;
R++;
}
while(R > Q[i].r){
R--;
ans = (ans + Comb(R, L)) % Mod * rfac[2] % Mod;
}
Ans[Q[i].id] = ans % Mod;
}
for(int i = 1; i <= n; i++) printf("%lld\n", Ans[i]);
return 0;
}