题目背景
小TY的同学HF也想创作艺术
HF只有一块长条状的画布(画条),所以每一次涂色只能涂上连续几个单位的颜料,同样新的颜料可以完全覆盖旧的颜料
由于他的颜料同样非常傲娇,每次涂完要等上1day才能完全干,只有旧颜料干了以后才能用新颜料覆盖
现在小HF用了2017个年头终于画出了一个大作品,自己非常满意
现在他想复制这份作品
题目描述
现在给你一个长度为N(N≤1e5)的画条
上面有若干种颜色,每位的数字表示一种颜色,0表示没有涂色
为了快捷,每次涂色可以用一种颜色填充一个区间,同一种颜色只能使用一次
每次可以涂色好几次,但是这些区间必须分别连续切两两不能相交
然后等待1day油漆干了后再同样操作,输出创作完成并全干了后的最少时间
输入输出格式
输入格式:
第一行为N,画条长度
一下N行每行一个数表示颜色
输出格式:
输出一个整数表示最少天数。数据若不合法则输出-1
输入输出样例
输入样例#1:
7 0 1 4 5 1 3 3
输出样例#1:
2
说明
In this example, the interval of color 1 must be painted in an earlier round than the intervals of colors 4 and 5, so at least two rounds are needed.
样例解释:
第一次可以把1颜色和3颜色填充,变成
0 1 1 1 1 3 3
等待1Day后再填充颜色4和颜色5,变成
0 1 4 5 1 3 3
在等待一Day油漆干了后创作完成
所以答案是2
感谢 @ Night_Aurora 贡献翻译
方案1 : 拓扑排序
记录头和尾,然后理清楚每种颜色的关系,并对入度为0的点进行排序,感觉好复杂,虽然我一开始也是这样想的
这样首先会炸内存,时间也有可能会炸
方案2 : 栈
因为不管颜色混成怎么样的一坨,时间都是最高的层数,没毛病吧,所以我们就直接用栈了
首先记录当前的点是哪一个点的开头或者结尾,如果不是就为0
90代码
#include <iostream>
using namespace std ;
const int N = 1e5 + 10 ;
int n , a[N] ;
int s[N] , t[N] ; //s为当前点是哪一个点的开头,t表示当前点是那一个点的结尾
int x[N] , y[N] ;
int top , ans = 0 ; //top表示栈顶,ans表示最大值
int main() {
cin >> n ;
for ( int i = 1 ; i <= n ; i ++ ) {
cin >> a[i] ; y[a[i]] = i ;
if ( x[a[i]] == 0 ) x[a[i]] = i ;
}
for ( int i = 1 ; i <= n ; i ++ ) {
if ( x[i] != 0 ) s[x[i]] = i ;
if ( y[i] != 0 ) t[y[i]] = i ;
}
for ( int i = 1 ; i <= n ; i ++ ) { //枚举每一个点
if ( a[i] == 0 ) { //如果中断了
if ( top != 0 ) { //如果栈里面还有颜色没有结束
cout << "-1" << endl ; //就直接放回-1
return 0 ;
}
continue ;
}
if ( s[i] != 0 ) top ++ , ans = max ( ans , top ) ; //如果这是开头,就top++
if ( t[i] != 0 ) top -- ; //否则就top-- , 注意一个点可能是开头和结尾
}
cout << ans << endl ;
return 0 ;
}
这个方法很明显是不对的,能过90%的数据已经是个奇迹了
原因就是这个代码只判断了0打断颜色的情况,比较片面
比如说这个数据:
5
1
2
1
2
1
代码输出2
正确答案应该是-1
能过90分应该是因为数据很大,而且有多个出现错误的地方
所以我们还要再打一个栈的数组,不能只保留栈顶
100分代码
#include <iostream>
using namespace std ;
const int N = 1e5 + 10 ;
int n , a[N] ;
int s[N] , t[N] ;
int x[N] , y[N] ;
int top , sta[N] , ans = 0 ;
int main() {
//freopen( "testdata.in","r",stdin ) ;
cin >> n ;
for ( int i = 1 ; i <= n ; i ++ ) {
cin >> a[i] ;
if ( a[i] == 0 ) continue ;
y[a[i]] = i ;
if ( x[a[i]] == 0 ) x[a[i]] = i ;
}
for ( int i = 1 ; i <= n ; i ++ ) {
if ( x[i] != 0 ) s[x[i]] = i ;
if ( y[i] != 0 ) t[y[i]] = i ;
}
for ( int i = 1 ; i <= n ; i ++ ) {
if ( s[i] != 0 ) sta[++top] = s[i] , ans = max ( ans , top ) ;
if ( sta[top] != a[i] ) { cout << "-1" << endl ; return 0 ; } //如果当前的颜色不是最上面那层的颜色,说明数据有误
if ( t[i] != 0 ) top -- ; //到终点就出栈
}
cout << ans << endl ; //输出
return 0 ;
}
小TY的同学HF用2017年创作了一幅艺术作品,需要复制。给定一个长度为N的画条,含有不同颜色,每次只能用一种颜色填充连续区间,且必须等待1天颜料干透。求复制并全干的最少天数。若无法完成则输出-1。题解中提到了拓扑排序和栈的解决方案。

477

被折叠的 条评论
为什么被折叠?



