题意:

给定一个n图片说明n的矩阵,一开始上面没有任何颜色(也就是都为0)。之后进行n图片说明n次染色,每次选择一个[1,n图片说明n]的颜色,且每种颜色都只会被选择一次。然后在矩阵上选择任意大小和任意位置的子矩阵进行染色,规定后面的染色会覆盖前面的染色。在给出矩阵最终的染色情况下,问第一次染色选择的颜色种类可能有多少种。

分析:

如果(x,y)处染色的次数大于等于2,那么(x,y)处的颜色肯定不能作为第一次染色选择的颜色。因此我们用一个矩阵S,S[i][j]表示(i,j)处的染色次数,初值均为0。然后对每种颜色记录他的左上角点和右下角点,使得这两点确定的矩阵内所有元素加一,在这里我们可以使用二维差分数组进行优化。之后判断每个位置的S[i][j],若S[i][j]大于等于2,则置(i,j)处的颜色的标记数组为0,表示该种颜色无法用于第一次染色。之后用ans统计一遍标记数组从1~n图片说明n中1的个数即可。
写完以上思想的代码快速交了一发,结果过了90%,肯定是还有什么特殊情况没有考虑。我们考虑这种情况:假如给出的矩阵里面只有一种颜色,那么通过以上思想求出的答案是n图片说明n,但是答案显然是n图片说明n-1才对。因此我们特判一下这种情况,就能顺利通过此题了。

代码:

#include<bits/stdc++.h>
using namespace std;

int a[1005][1005],S[1005][1005]={0};
int xmi[1000005],xmx[1000005],ymi[1000005],ymx[1000005];
bool V[1000005];
int main()
{
    int i,j,n,id,ans=0;
    scanf("%d",&n);
    for(i=1;i<=n*n;i++)xmi[i]=ymi[i]=1e9,xmx[i]=ymx[i]=0,V[i]=1;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]),id=a[i][j];
            xmi[id]=min(xmi[id],i);
            xmx[id]=max(xmx[id],i);
            ymi[id]=min(ymi[id],j);
            ymx[id]=max(ymx[id],j);
        }
    for(i=1;i<=n*n;i++)
    {
        if(!xmx[i])continue;
        ans++;
        S[xmi[i]][ymi[i]]++;
        S[xmi[i]][ymx[i]+1]--;
        S[xmx[i]+1][ymi[i]]--;
        S[xmx[i]+1][ymx[i]+1]++;
    }
    if(ans==1){printf("%d\n",n*n-1);return 0;}
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            S[i][j]+=S[i-1][j]+S[i][j-1]-S[i-1][j-1];
            if(S[i][j]>=2)V[a[i][j]]=0;
        }
    for(ans=0,i=1;i<=n*n;i++)ans+=V[i];
    printf("%d\n",ans);
    return 0;
}