0
点赞
收藏
分享

微信扫一扫

BZOJ 4776 Usaco2017 Open Modern Art


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

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

开一个新的n∗n的矩阵cnt,初始全0
对于每个数字统计出出现的最上u最下d最左l最右r,然后就能框出一个矩形,把cnt[u,d][l,r]加上1,表示有一个矩形在这个位置至少涂了一次
如果一个格子的cnt>1,说明有超过一个矩形在这里涂了数字,那么这个格子最终的数字一定不能最先涂
剩下的就是能最先涂的数字。
特殊情况:n≠1且最终矩阵里除了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 条评论