標籤:cut sub ons pre problem bool can 預先處理 acm
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6333
解題心得:
- 這個題可以說是十分精彩了,首先推組合數學的公式,其中一個很重要的公式是Cnm = Cmn-1 + Cm-1n-1 這個公式知道楊輝三角的都明白,但是一看發現似乎沒啥用。但是可以以這個公式為基礎繼續推演下去。
- 設Snm = Cn1 + Cn2 + Cn3 + ...... Cnm 然後繼續使用上面的基本公式可以化成
- Sn m-1 = Sn m - Cn m
Sn m+1 = Sn m + Cn m+1
Sn+1 m = 2Sn m - Cn m
Sn m = (Sn+1 m + Cn m)/2
- 這些個公式看起來沒啥用,但是知道S的關係之間可以通過O(1)的複雜度來進行轉化,這樣就可以將105次詢問離線化處理,也就是用莫隊來維護。神奇阿,想破腦袋就是想不到阿。裡面的除法取餘的操作用逆元來處理,逆元可以先全與預先處理出來。
//// ┏┛ ┻━━━━━┛ ┻┓// ┃ ┃// ┃ ━ ┃// ┃ ┳┛ ┗┳ ┃// ┃ ┃// ┃ ┻ ┃// ┃ ┃// ┗━┓ ┏━━━┛// ┃ ┃ 神獸保佑// ┃ ┃ 代碼無BUG!// ┃ ┗━━━━━━━━━┓// ┃ ┣┓// ┃ ┏┛// ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛// ┃ ┫ ┫ ┃ ┫ ┫// ┗━┻━┛ ┗━┻━┛#include <bits/stdc++.h>using namespace std;const int maxn = 1e5+100;const int MOD = 1e9+7;typedef long long ll;struct Query { ll n, m, B, pos, ans;}q[maxn];ll unit, ans, fac[maxn], inv[maxn], t, rev2;ll quick_pow(ll a, ll b) { ll res = 1; while(b) { if(b&1) res = res * a % MOD; a = a * a % MOD; b >>= 1; } return res;}void get_fac() { //預先處理出階乘和逆元 fac[0] = 1; fac[1] =1; for(int i=2;i<maxn;i++) { fac[i] = i * fac[i-1] % MOD; } //神奇的操作 inv[maxn-1] = quick_pow(fac[maxn-1], MOD-2); for(int i=maxn-2;i>=0;i--) { inv[i] = inv[i+1] * (i + 1) % MOD; }}bool cmp1(Query a, Query b) { if(a.B == b.B) return a.m < b.m; return a.B < b.B;}bool cmp2(Query a, Query b) { return a.pos < b.pos;}void init() { unit = sqrt(maxn); get_fac(); scanf("%lld", &t); for(int i=0;i<t;i++) { scanf("%lld%lld", &q[i].n, &q[i].m); q[i].B = q[i].n/unit; q[i].pos = i; } rev2 = quick_pow(2, MOD-2); sort(q, q+t, cmp1);}ll C(ll n, ll m) {//得到c(n, m)的組合 ll ans = fac[n] * inv[n-m] % MOD * inv[m] % MOD; return ans;}void addL(ll l, ll r) { ans = ((2 * ans % MOD) + MOD - C(l, r)) % MOD;}void cutL(ll l, ll r) { ans = (ans + C(l-1, r) % MOD) * rev2 % MOD;}void addR(ll l, ll r) { ans = (ans + C(l, r+1)) % MOD;}void cutR(ll l, ll r) { ans = (ans + MOD - C(l, r)) % MOD;}int main() { init(); ll l=1, r = 1; ans = 2; for(int i=0;i<t;i++) {//離線莫隊處理 int L = q[i].n; int R = q[i].m; while(l < L) addL(l++, r); while(l > L) cutL(l--, r); while(r > R) cutR(l, r--); while(r < R) addR(l, r++); q[i].ans = ans; } sort(q, q+t, cmp2); for(int i=0;i<t;i++) { printf("%lld\n",q[i].ans); } return 0;}
HDOJ:6333-Problem B. Harvest of Apples(組合數學+莫隊演算法+逆元)