1. 程式人生 > >Luogu 2154 [SDOI2009]虔誠的墓主人

Luogu 2154 [SDOI2009]虔誠的墓主人

分享 esp 我們 open index 一個空格 nod 狀態 nom

弄了很久,狀態很爛……

首先發現可用的點一共只有$1e5$個,所以可以離散化坐標來方便計算。

發現對於一個空格,設它的上、下、左、右分別有$u, d, l, r$個點,它產生的貢獻是$\binom{u}{k} * \binom{d}{k} * \binom{l}{k} * \binom{r}{k}$,這樣子一共要計算$n^{2}$個點,時間承受不了,考慮使用掃描線優化。

我們可以掃$x$坐標或$y$坐標,這樣子在掃一條線的過程中可以把上面的式子提出來兩項,然後剩下的兩項我們考慮用一個數據結構優化計算。

假設我們掃$y$坐標,那麽我們可以用一個樹狀數組維護前後兩個$y$坐標中間的$x$坐標產生的貢獻,即$\sum \binom{cnt}{k} * \binom{sum - cnt}{k}$。

這樣子每掃一個點可以動態維護一下,把它之前的貢獻清空,加上之後產生的貢獻,即$s_{x} += \sum \binom{cnt + 1}{k} * \binom{sum - cnt - 1}{k} - \sum \binom{cnt}{k} * \binom{sum - cnt}{k}$。

另外不是很懂這題的取模,多取了幾個之後發現爆負數了,抄了hzwer的代碼。

註意把$x$和$y$一起離散化。

時間復雜度$O(nlogn)$。

Code:

技術分享圖片
#include <cstdio>
#include <cstring>
#include <algorithm>
using
namespace std; typedef long long ll; const int N = 1e5 + 5; const ll P = 2147483648LL; int n, m, w, K, tot = 0, in[N << 1], cnt[N]; ll c[N][12], sumx[N], sumy[N]; struct Node { int x, y; } a[N]; bool cmp(const Node &u, const Node &v) { if(u.y == v.y) return u.x < v.x;
else return u.y < v.y; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > 9|| ch < 0; ch = getchar()) if(ch == -) op = -1; for(; ch >= 0 && ch <= 9; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } namespace BinaryIndexTree { ll s[N << 1]; #define lowbit(p) (p & (-p)) inline void modify(int p, ll v) { for(; p <= tot; p += lowbit(p)) s[p] += v, s[p] %= P; } inline ll query(int p) { ll res = 0LL; for(; p > 0; p -= lowbit(p)) res += s[p], res %= P; return res; } } using namespace BinaryIndexTree; int main() { read(n), read(m), read(w); for(int i = 1; i <= w; i++) { read(a[i].x), read(a[i].y); in[++tot] = a[i].x, in[++tot] = a[i].y; } read(K); c[0][0] = 1LL; for(int i = 1; i <= w; i++) { c[i][0] = 1LL; for(int j = 1; j <= min(i, K); j++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P; } sort(in + 1, in + 1 + tot); tot = unique(in + 1, in + 1 + tot) - in - 1; for(int i = 1; i <= w; i++) { a[i].x = lower_bound(in + 1, in + tot + 1, a[i].x) - in; a[i].y = lower_bound(in + 1, in + tot + 1, a[i].y) - in; sumx[a[i].x]++, sumy[a[i].y]++; } /* for(int i = 1; i <= w; i++) printf("%d %d\n", a[i].x, a[i].y); */ sort(a + 1, a + 1 + w, cmp); ll ans = 0LL; int cnty; for(int i = 1; i <= w; i++) { if(i > 1 && a[i].y == a[i - 1].y) { ++cnty; ll tmp1 = query(a[i].x - 1) - query(a[i - 1].x); ll tmp2 = c[cnty][K] * c[sumy[a[i].y] - cnty][K]; ans += tmp1 * tmp2; ans %= P; } else cnty = 0; cnt[a[i].x]++; modify(a[i].x, (c[cnt[a[i].x]][K] * c[sumx[a[i].x] - cnt[a[i].x]][K] - c[cnt[a[i].x] - 1][K] * c[sumx[a[i].x] - cnt[a[i].x] + 1][K]) % P); } if(ans < 0) ans += P; printf("%lld\n", ans); return 0; }
View Code

Luogu 2154 [SDOI2009]虔誠的墓主人