BZOJ 4776 Usaco2017 Open Modern Art

PoPoQQQ發表於2017-03-22

題目大意:給定一個nn

n*n
的矩陣,初始都為0
0
,選擇一個1
1
nn
n*n
的排列,然後按照這個排列的順序,每次選擇這個矩陣的一個非空子矩形,然後塗上當前數字。
現在給定最終的矩陣,求哪些數字可能是排列的第一位。

寫輸入法寫成傻逼回來換換腦子……

開一個新的nn

n*n
的矩陣cnt
cnt
,初始全0
0

對於每個數字統計出出現的最上u
u
最下d
d
最左l
l
最右r
r
,然後就能框出一個矩形,把cnt[u,d][l,r]
cnt[u,d][l,r]
加上1
1
,表示有一個矩形在這個位置至少塗了一次
如果一個格子的cnt>1
cnt>1
,說明有超過一個矩形在這裡塗了數字,那麼這個格子最終的數字一定不能最先塗
剩下的就是能最先塗的數字。
特殊情況:n1
n\neq1
且最終矩陣裡除了0
0
外只有一種數字,那麼這個數字肯定不能先塗,要從答案中扣除。

時間複雜度O(n2)

O(n^2)

#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;
}

相關文章