POJ现代艺术

POJ现代艺术

原题链接

POJ现代艺术

题目描述

在对二维艺术作品感到厌烦之后,伟大的艺术牛Picowso决定从事创作一项更为小众的艺术形式,一维画。
尽管目前她的画作可以用一个由颜色组成的长度为N(1-100000)的数组表示,但她的创作风格依然保持不变:从一张空白的矩形画布上,不断地画上一些矩形,在一维的情况下,这些矩形就只是一个区间。她用N种颜色,颜色编号为1~N进行创作,每种颜色只使用一次,之后使用的颜色可以完全的覆盖之前在相同位置上的颜色。
令Picowso感到十分沮丧的是,她的竞争对手Moonet似乎弄明白了如何复制她的这些一维画作,Moonet会画一些不相交的间隔,等待这些颜色晾干,然后再画另外的一些间隔,直到画完。Moonet每次每种颜色最多只能画一个间隔,但是他可以一次画不同颜色不相交的多个间隔,只要这些间隔没有重叠部分。之后Moonet再进行下一轮绘制。请计算Moonet为了复制一幅画需要画几个回合。

输入

第一行是一个整数N,之后N行包含了N个整数,范围0到N表示纸带每个格点的颜色,0表示没有涂色。

输出

输出一行,需要复制这幅画作的最少回合数,如果这幅画不可能是Picowso的画作输出-1(比如说这幅画不可能是通过一次在一条上画一层的方法进行创作的)

样例输入

7
0
1
4
5
1
3
3

样例输出

2

核心思路

  • 先考虑一幅合法画作,对于颜色 c c c,设其在画作中第一次出现的位置为 L p L_p Lp,最后一次出现的位置为 U p U_p Up 。对于一个画作中的一个位置 i i i,用题目中描述的方法复刻画作时,这个位置至少要被画 ∣ { p : L p < = i < = U p } ∣ |\{p:L_p<=i<=U_p\}| {p:Lp<=i<=Up}这么多次。通俗的来说,就是覆盖这个点的颜色区间的个数。
  • 我们可以用一个栈 s t a sta sta来记录覆盖当前位置的颜色区间,这个位置至少要画的次数也就是当前栈的大小,设为 s t a ( i ) sta^{(i)} sta(i)。那么答案即为 max ⁡ i { s t a ( i ) } \max\limits_i \{sta^{(i)} \} imax{sta(i)}(可以从木桶原理解释为什么取 max ⁡ \max max)。

栈的维护

  • 入栈:每碰到一个与当前栈顶颜色不同的颜色,意味着一个新的颜色区间的开始,将其入栈。
  • 出栈:当遍历到栈顶元素最后出现的位置时,区间结束,出栈。可以用一个 e n d _ p o s end\_pos end_pos数组记录每个颜色区间的末端。

非法画作

  • 一幅非法画作,如 ( 1    2    1    2    1 ) (1\;2\;1\;2\;1) 12121其特点在于:在栈顶颜色的区间内画上了在原画作中位置在栈顶颜色之前的颜色。即 ∃ i , j      s . t . ( i ∈ c o v e r ( j ) & & j ∈ c o v e r ( i ) ) \exist i,j \;\;s.t.(i \in cover(j) \&\& j \in cover(i)) i,js.t.(icover(j)&&jcover(i)) ,从 i的角度来看,就是 j j j出现在我之前,并且在我的覆盖范围又碰到 j j j。于是我们可以用一个 V i s i t Visit Visit数组来记录所有已出现的颜色。

AC代码

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

int end_pos[MAXN], canvas[MAXN];
int N, result, flag = 1; /* flag = 1 means legal */
char Visit[MAXN];
stack<int> sta;

int main(){
	scanf("%d", &N);
	for(int i = 1;i <= N;i += 1){
		scanf("%d", canvas + i);
		// record the end point of every interval
		end_pos[canvas[i]] = i; 
	}
	
	// view 0 as the first color that covers the entire canvas
	Visit[0] = 1;
	end_pos[0] = N + 1;
	sta.push(0);  
	
	// loop through the canvas
	for(int i = 1;i <= N && flag;i += 1){
		if(sta.top() != canvas[i]){
			// an illegal painting
			if(Visit[canvas[i]])
				flag = 0;
			sta.push(canvas[i]);
		}
		Visit[canvas[i]] = 1;
		result = max(result, (int)sta.size());
		// an interval ends
		if(i == end_pos[canvas[i]])
			sta.pop();
	}
	// result-1 because the extra 0 
	printf("%d\n", (flag ? result - 1: -1));
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值