[BZOJ 1227] 虔诚的墓主人

这里写图片描述

题解:长这样的题好像都有固定套路…所有点按坐标排序、处理组合数,然后用树状数组维护奇怪的信息…….编不下去了 黄学长的题解

AC Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline void read(int &x){x=0;char c;while((c=getchar())<'0'||c>'9');for(x=c-'0';(c=getchar())>='0'&&c<='9';x=x*10+c-'0');}
const int mo = 2147483647;
const int N = 100010 ;

int C[N][11], w, k;

void init_Calc()
{
    C[0][0] = 1;
    for (int i = 1; i <= w; ++i)
    {
        C[i][0] = 1;
        for (int j = 1; j <= k; ++j)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) & mo;
    }
}

struct Data
{
    int x, y;

    inline bool operator < (const Data & b) const 
    {
        return y < b.y || (y == b.y && x < b.x);
    }
}p[N];

int TX[N], TY[N], cX, cY;
int Cnt[N], down[N], left[N], right[N];

namespace BIT
{
    int c[N];

    inline void add(int p, int v)
    {
        while (p <= cX) c[p] += v, p += p & -p;
    }
    inline int ask(int p)
    {
        int ret = c[p];
        while (p -= p & -p) ret += c[p];
        return ret;
    }
}

int main()
{
    read(w), read(w), read(w);
    for (int i = 1; i <= w; ++i)
    {
        read(p[i].x), read(p[i].y);
        TX[i] = p[i].x, TY[i] = p[i].y;
    }

    read(k);
    init_Calc();

    sort(TX + 1, TX + w + 1);
    cX = unique(TX + 1, TX + w + 1) - TX - 1;
    sort(TY + 1, TY + w + 1);
    cY = unique(TY + 1, TY + w + 1) - TY - 1;
    sort(p + 1, p + w + 1);

    for (int i = 1; i <= w; ++i)
    {
        p[i].x = lower_bound(TX + 1, TX + cX + 1, p[i].x) - TX;
        p[i].y = lower_bound(TY + 1, TY + cY + 1, p[i].y) - TY;
        left[i] = (p[i].y == p[i - 1].y ? left[i - 1] + 1 : 1);
        Cnt[p[i].x]++;
    }
    for (int i = w; i; --i) 
        right[i] = (p[i].y == p[i + 1].y ? right[i + 1] + 1 : 1);

    using namespace BIT;
    int ans = 0, i = 1;
    p[w + 1].y = -1;

    while (i <= w)
    {
        int l = i;
        while (p[l].y == p[l + 1].y)
        {
            ans += C[left[l]][k] * C[right[l + 1]][k] * (ask(p[l + 1].x - 1) - ask(p[l].x));
            l++;
        }
        while (i <= l)
        {
            int x = p[i].x;
            add(x, C[down[x] + 1][k] * C[Cnt[x] - down[x] - 1][k] - C[down[x]][k] * C[Cnt[x] - down[x]][k]);
            down[x]++, i++;
        }
    }

    printf("%d\n", ans & mo);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值