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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/CzxingcHen/p/9615033.html