• Luogu 2154 [SDOI2009]虔诚的墓主人


    弄了很久,状态很烂……

    首先发现可用的点一共只有$1e5$个,所以可以离散化坐标来方便计算。

    发现对于一个空格,设它的上、下、左、右分别有$u, d, l, r$个点,它产生的贡献是$inom{u}{k} * inom{d}{k} * inom{l}{k} * inom{r}{k}$,这样子一共要计算$n^{2}$个点,时间承受不了,考虑使用扫描线优化。

    我们可以扫$x$坐标或$y$坐标,这样子在扫一条线的过程中可以把上面的式子提出来两项,然后剩下的两项我们考虑用一个数据结构优化计算。

    假设我们扫$y$坐标,那么我们可以用一个树状数组维护前后两个$y$坐标中间的$x$坐标产生的贡献,即$sum inom{cnt}{k} * inom{sum - cnt}{k}$。

    这样子每扫一个点可以动态维护一下,把它之前的贡献清空,加上之后产生的贡献,即$s_{x} += sum inom{cnt + 1}{k} * inom{sum - cnt - 1}{k} - sum inom{cnt}{k} * inom{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
    ", 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
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Android 废弃方法属性解决
    Android RecycleView分组
    Android 第三方库FlycoTabLayout
    Android 自定义dialog出现的位置
    Android 底部弹窗实现
    Android 自定义设置布局
    Android 微信、qq分享文本 (Intent)
    SpringBoot关于跨域的三种解决方案
    记录一次通用Mapper+自定义mapper出现的问题分析以及排查
    IDEA配置Maven+新建Maven项目
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9615033.html
Copyright © 2020-2023  润新知