T2画画
画画(paint)
【题目描述】
小A是一名画家。
现在有一张大小为的网格图,小A用 种颜色在网格图上作画。
其中第 种颜色编号为 ,初始时网格图中每个格子都没有颜色,编号
为0。
已知每种颜色小A都会使用且只使用一次,但使用的顺序是未知的。
使用一种颜色时需要选定一个连续的子矩阵,将该子矩阵涂上这种颜
色。
后涂的颜色会覆盖之前的颜色。
现在给出小A画完后的图,问有多少种颜色可能是小A最先使用的。
【输入格式】
从paint.in中读入数据。
第一行三个数 , , ,表示网格图的大小和颜色的数量。
之后 行,每行 个数,描述网格图中每个格子的颜色。
【输出格式】
将答案输出到paint.out。
一个数,表示有多少种颜色可能时小A最先使用的。
【样例输入】
3 4 8
2 3 0 5
2 3 7 7
2 7 7 7
【样例输出】
7
【样例解释】
只有3号颜色不可能是最先使用的。
【数据规模与约定】
对于30%的数据,
对于60%的数据,
对于另外20%的数据,
对于100%的数据,
做法 :
对于每种颜色求出该颜色的四个边界,之后枚举k个边界构成的矩阵中每个元素,如果不等于该颜色,说明那种颜色要覆盖其他颜色,就标记那种颜色不能最先使用, 。
复杂度 。优化:设矩阵宽为 (有 行),则 。对于一个矩阵,我们每行第一个位置打个这种颜色的标记,在最后一个位置之后删除这个标记。 总共要打 个标记。最后统计答案不是按颜色遍历,而是直接扫描整张画板,到一个位置更新一下标记,更新的个数肯定也是 个。怎么判断当前点是否 呢? 如果当前身上带了大于一个标记,肯定就不可能,因为一个点不可能同时是两种及以上颜色。如果身上只有一个标记,直接判断即可。
还要注意特判整张图只有一种颜色的情况(答案为 )。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, k, a[N];
int mni[N], mxi[N], mnj[N], mxj[N];
vector<int> add[N], era[N];
bool cant[N];
int now, tot;
bool tong[N]; int cnt;
inline int p(int i, int j)
{
return (i - 1) * m + j;
}
inline void gx(int c)
{
if(!cant[c]) cant[c] = true, --k;
}
int x; char v;
inline int read()
{
x = 0;
while(!isdigit(v)) v = getchar();
while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
return x;
}
int main()
{
freopen("paint9.in", "r", stdin);
freopen("a.out", "w", stdout);
memset(mni, 101, sizeof mxi);
memset(mnj, 10001, sizeof mxj);
n = read(), m = read(), k = read();
int t, c;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
if(n > m) t = (j - 1) * n + i;
else t = (i - 1) * m + j;
a[t] = read();
}
if(n > m) swap(n, m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
c = a[p(i, j)];
if(!tong[c]) tong[c] = true, ++cnt;
mni[c] = min(mni[c], i);
mxi[c] = max(mxi[c], i);
mnj[c] = min(mnj[c], j);
mxj[c] = max(mxj[c], j);
}
for(int i = 1; i <= k; ++i)
for(int l = mni[i]; l <= mxi[i]; ++l)
{
add[p(l, mnj[i])].push_back(i); //加标记
era[p(l, mxj[i])].push_back(i); //减标记
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
t = p(i, j);
for(int l = 0; l < add[t].size(); ++l) now ^= add[t][l], ++tot; //此处,因为我们只需要知道只剩一种颜色时的情况,可以用异或更新(小技巧增加了!),感谢wyn大神的点拨
if(tot > 1 || now ^ a[t]) gx(a[t]);
for(int l = 0; l < era[t].size(); ++l) now ^= era[t][l], --tot;
}
if(cnt == 1) --k;
cout << k;
return 0;
}
for(int i = 1; i <= n; ++i)
for(int j = 1, t; j <= m; ++j)
{
t = p(i, j);
for(int l = 0; l < add[t].size(); ++l) now.insert(add[t][l]);//之前用set存的蠢
if(now.size() > 1 || ((*now.begin()) ^ a[t])) gx(a[t]);
for(int l = 0; l < era[t].size(); ++l) now.erase(era[t][l])
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具