BZOJ 4776 Usaco2017 Open Modern Art

题目大意:给定一个 nn 的矩阵,初始都为 0 ,选择一个1 nn 的排列,然后按照这个排列的顺序,每次选择这个矩阵的一个非空子矩形,然后涂上当前数字。
现在给定最终的矩阵,求哪些数字可能是排列的第一位。

写输入法写成傻逼回来换换脑子……

开一个新的 nn 的矩阵 cnt ,初始全 0
对于每个数字统计出出现的最上u最下 d 最左l最右 r ,然后就能框出一个矩形,把cnt[u,d][l,r]加上 1 ,表示有一个矩形在这个位置至少涂了一次
如果一个格子的cnt>1,说明有超过一个矩形在这里涂了数字,那么这个格子最终的数字一定不能最先涂
剩下的就是能最先涂的数字。
特殊情况: n1 且最终矩阵里除了 0 外只有一种数字,那么这个数字肯定不能先涂,要从答案中扣除。

时间复杂度O(n2)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1010
using namespace std;

int n,cnt,ans;

int a[M][M],b[M][M];
int u[M*M],d[M*M],l[M*M],r[M*M];
bool killed[M*M];

int main()
{
    cin>>n;
    memset(u,0x3f,sizeof u);
    memset(l,0x3f,sizeof l);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j])
            {
                if(u[a[i][j]]==0x3f3f3f3f)
                    ++cnt;
                u[a[i][j]]=min(u[a[i][j]],i);
                d[a[i][j]]=max(d[a[i][j]],i);
                l[a[i][j]]=min(l[a[i][j]],j);
                r[a[i][j]]=max(r[a[i][j]],j);
            }
        }
    for(int i=1;i<=n*n;i++)
        if(u[i]!=0x3f3f3f3f)
        {
            b[u[i]][l[i]]++;
            b[d[i]+1][l[i]]--;
            b[u[i]][r[i]+1]--;
            b[d[i]+1][r[i]+1]++;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(a[i][j] && b[i][j]>1)
                killed[a[i][j]]=true;
    for(int i=1;i<=n*n;i++)
        if(!killed[i])
            ++ans;
    if(cnt==1 && n!=1)
        --ans;
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值