【Codeforces815D】Karen and Cards

题意:
给定N张卡牌,每张卡牌有三个属性 ai,bi,ci
现在给出三个数 p,q,r ,分别表示三个属性的上限。问有多少种不同的卡牌,能压制给定的 n 张卡牌(只要三个属性有两个的值严格大于另一卡牌即可)。其中属性值一定是正整数。

首先肯定要按某一维排序,我们不妨排序ci
从大到小枚举 c ,我们发现每次的答案都是一个类似于阶梯的图。然后(好吧我也不知道)似乎先算出最后的所有的卡牌都加入后的阶梯图,统计a,b维的前缀和,然后每个 c 应该分类讨论一下就可以了。
时间复杂度O(nlogn+p+q+r)

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 500009
using namespace std;
int n,p,q,r,A[N],B[N];
ll Ans,sum,sum_A[N],sum_B[N];
struct node
{
    int a,b,c;
    bool operator <(const node &rhs) const
    {
        return c>rhs.c;
    }
}a[N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int main()
{
    n=read(),p=read(),q=read(),r=read();
    for (int i=1;i<=n;i++)
        a[i].a=read(),a[i].b=read(),a[i].c=read();
    sort(a+1,a+n+1);
    for (int i=1;i<=n;i++) A[a[i].a]=max(A[a[i].a],a[i].b);
    for (int i=1;i<=n;i++) B[a[i].b]=max(B[a[i].b],a[i].a);
    for (int i=p;i;i--) A[i]=max(A[i],A[i+1]);
    for (int i=q;i;i--) B[i]=max(B[i],B[i+1]);
    for (int i=1;i<=p;i++) sum+=(ll)q-A[i];
    for (int i=1;i<=p;i++) sum_A[i]=sum_A[i-1]+(ll)q-A[i];
    for (int i=1;i<=q;i++) sum_B[i]=sum_B[i-1]+(ll)p-B[i];
    int now=1,MaxA=0,MaxB=0;
    for (int c=r;c;c--)
    {
        while (now<=n&&a[now].c==c)
        {
            MaxA=max(MaxA,a[now].a+1);
            MaxB=max(MaxB,a[now].b+1);
            now++;
        }
        if (A[MaxA]<MaxB) Ans+=(ll)(p-MaxA+1)*(q-MaxB+1);
        else Ans+=(ll)sum-sum_A[MaxA-1]-sum_B[MaxB-1];
    }
    printf("%lld\n",Ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值