Luogu 2154 [SDOI2009]虔诚的墓主人
弄了很久,状态很烂……
首先发现可用的点一共只有$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; }