USACO 2019 February Contest, Silver Problem 2. Painting the Barn —— 枚举,前缀和

This way

题意:

给你n个矩形,你现在可以添加两个矩形,使得被k个矩形覆盖的面积最大。

题解:

这两个新加入的矩形要么是互为上下或者互为左右的关系,那么我们要处理出来第i行上面最大的情况和第i行下面最大的情况,第i列左边最大的情况和第i列右边的最大的情况。那么我们怎么维护最大值?我们可以先用二维前缀和求出200*200区间的所有覆盖情况,然后将k-1置为1,k置为-1,其它置为0,再自底向上求一个前缀和,这样的话我们枚举上下区间做区间最大子矩阵的时候就会方便一点,同时维护4个数组的值,最后for一遍求最大值。

#include<bits/stdc++.h>
using namespace std;
int up[205],down[205],lef[205],rig[205];
int mp[205][205];
int main()
{
    int n,k,l,r,u,d;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&l,&d,&r,&u),mp[l][d]++,mp[r][d]--,mp[l][u]--,mp[r][u]++;
    for(int i=0;i<=200;i++)
        for(int j=0;j<=200;j++)
            if(i>0)
                mp[i][j]+=mp[i-1][j];
    int ans=0;
    for(int i=0;i<=200;i++)
    {
        for(int j=0;j<=200;j++)
        {
            if(j>0)
                mp[i][j]+=mp[i][j-1];
            ans=ans+(mp[i][j]==k?1:0);
        }
    }
    for(int i=0;i<200;i++)
    {
        for(int j=0;j<200;j++)
        {
            if(mp[i][j]==k)
                mp[i][j]=-1;
            else if(mp[i][j]==k-1)
                mp[i][j]=1;
            else
                mp[i][j]=0;
        }
    }
    int mx=0;
    int val[205]={0};
    for(d=0;d<200;d++)
    {
        for(int i=0;i<200;i++)
            val[i]=0;
        for(u=d;u<200;u++)
        {
            mx=0;
            for(int i=0;i<200;i++)
                val[i]+=mp[i][u];
            for(int i=0;i<200;i++)
            {
                mx=max(0,mx+val[i]);
                up[d]=max(up[d],mx);
                down[u]=max(down[u],mx);
            }
        }
    }
    for(l=0;l<200;l++)
    {
        for(int i=0;i<200;i++)
            val[i]=0;
        for(r=l;r<200;r++)
        {
            mx=0;
            for(int i=0;i<200;i++)
                val[i]+=mp[r][i];
            for(int i=0;i<200;i++)
            {
                mx=max(0,mx+val[i]);
                rig[l]=max(rig[l],mx);
                lef[r]=max(lef[r],mx);
            }
        }
    }
    mx=0;
    for(int i=1;i<200;i++)
        lef[i]=max(lef[i],lef[i-1]),down[i]=max(down[i],down[i-1]);
    for(int i=200-1;i>=0;i--)
        rig[i]=max(rig[i],rig[i+1]),up[i]=max(up[i],up[i+1]);
    for(int i=1;i<=200;i++)
        mx=max(mx,lef[i-1]+rig[i]),mx=max(mx,up[i]+down[i-1]);
    printf("%d\n",ans+mx);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值