题意
$T$个询问,每次询问给出$n,k$,你需要回答
数据范围:$1le Tle 100000, 0le n,kle 100000$
莫队
这题需要用普通莫队算法。
我们将每个询问$(n,k)$离线存下来,并用莫队处理区间问题的方法将其分块后排序。($n$当做左端点,$k$当做右端点)
我们知道要想用莫队算法,就需要知道$(n,k)$的答案和$(n,k+1),(n,k-1),(n-1,k),(n+1,k)$这四种询问的答案的联系。也就是说当前指针指向$(n,k)$时,我们需要$O(1)$地算出上述询问的答案。
组合数
先找$(n,k)$的答案和$(n,k+1),(n,k-1)$的答案的关系。
很容易就能发现:
然后我们来找$(n,k)$和$(n-1,k),(n+1,k)$的关系,注意到有这个等式:
所以我们可以这么推:
然后反过来推出
综上所述:
注意到我们在转移时需要以$O(1)$的复杂度求出单个组合数,因为
所以预处理1-100000中每个数的逆元,以及阶乘的逆元,就能做到。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
#include <cmath> #include <algorithm> using namespace std ;#define MOD 1000000007ll #define MAXN 200005 typedef long long ll;typedef unsigned long long ull;#define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) ll () { char c = getchar(); ll ret = 0 ; while (c < '0' || c > '9' ) c = getchar(); while (c >= '0' && c <= '9' ) ret = ret * 10 + c - '0' , c = getchar(); return ret; } int N;ll blocklen, pn = 1 , pk = 0 , anst = 1 , inv[MAXN], mul[MAXN], mulinv[MAXN], ans[MAXN], inv2 = (MOD + 1 ) >> 1 ; struct query { ll n, k, id, block; } Q[MAXN]; bool cmp (query q1, query q2) { if (q1.block != q2.block) return q1.block < q2.block; else return q1.k < q2.k; } ll ask (ll n, ll m) { return ((mul[n] * mulinv[m]) % MOD * mulinv[n - m]) % MOD; } void move (int t) { switch (t) { case 1 : anst = ((anst + ask(pn, pk + 1 )) % MOD + MOD) % MOD, ++pk; break ; case 2 : anst = ((anst - ask(pn, pk)) % MOD + MOD) % MOD, --pk; break ; case 3 : anst = (((2 * anst) % MOD - ask(pn, pk)) % MOD + MOD) % MOD, ++pn; break ; case 4 : anst = ((inv2 * ((anst + ask(pn - 1 , pk)) % MOD)) % MOD + MOD) % MOD, --pn; break ; } } int main () { N = read(), blocklen = sqrt (N); int i; inv[1 ] = 1 , mul[0 ] = mulinv[0 ] = 1 ; for (i = 2 ; i <= 100000 ; ++i) inv[i] = ((MOD - MOD / i) * inv[MOD % i]) % MOD, mul[i] = (mul[i - 1 ] * (ll)i) % MOD; for (i = 1 ; i <= 100000 ; ++i) mul[i] = (mul[i - 1 ] * i) % MOD, mulinv[i] = (mulinv[i - 1 ] * inv[i]) % MOD; for (i = 1 ; i <= N; ++i) Q[i].n = read(), Q[i].k = read(), Q[i].id = i, Q[i].block = Q[i].n / blocklen; sort(Q + 1 , Q + N + 1 , cmp); for (i = 1 ; i <= N; ++i) { while (pn < Q[i].n) move(3 ); while (pn > Q[i].n) move(4 ); while (pk < Q[i].k) move(1 ); while (pk > Q[i].k) move(2 ); ans[Q[i].id] = anst; } for (i = 1 ; i <= N; ++i) printf ("%lldn" , ans[i]); return 0 ; }
原文:大专栏 题解 AT987 高桥君