T2画画

画画(paint)
【题目描述】
小A是一名画家。
现在有一张大小为n×m的网格图,小A用 k 种颜色在网格图上作画。
其中第 i 种颜色编号为 i,初始时网格图中每个格子都没有颜色,编号
为0。
已知每种颜色小A都会使用且只使用一次,但使用的顺序是未知的。
使用一种颜色时需要选定一个连续的子矩阵,将该子矩阵涂上这种颜
色。
后涂的颜色会覆盖之前的颜色。
现在给出小A画完后的图,问有多少种颜色可能是小A最先使用的。
【输入格式】
从paint.in中读入数据。
第一行三个数 n, m , k,表示网格图的大小和颜色的数量。
之后 n 行,每行 m 个数,描述网格图中每个格子的颜色。
【输出格式】
将答案输出到paint.out。
一个数,表示有多少种颜色可能时小A最先使用的。
【样例输入】
3 4 8
2 3 0 5
2 3 7 7
2 7 7 7
【样例输出】
7
【样例解释】
只有3号颜色不可能是最先使用的。
【数据规模与约定】
对于30%的数据,1n×m , k20
对于60%的数据,1n×m , k1000
对于另外20%的数据,1n×m105,k=1
对于100%的数据,1n×m , k105

做法 :

对于每种颜色求出该颜色的四个边界,之后枚举k个边界构成的矩阵中每个元素,如果不等于该颜色,说明那种颜色要覆盖其他颜色,就标记那种颜色不能最先使用, canti=true

复杂度 Θ(kmn) 。优化:设矩阵宽为 n (有 n 行),则 nn×m 。对于一个矩阵,我们每行第一个位置打个这种颜色的标记,在最后一个位置之后删除这个标记。 总共要打 n×k 个标记。最后统计答案不是按颜色遍历,而是直接扫描整张画板,到一个位置更新一下标记,更新的个数肯定也是 n×k 个。怎么判断当前点是否 canti=true 呢? 如果当前身上带了大于一个标记,肯定就不可能,因为一个点不可能同时是两种及以上颜色。如果身上只有一个标记,直接判断即可。

还要注意特判整张图只有一种颜色的情况(答案为 k1 )。

代码:

#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])
		}
posted @   Faker_yu  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示