1. 程式人生 > >[LuoguP3668][USACO17OPEN]現代藝術2

[LuoguP3668][USACO17OPEN]現代藝術2

[LuoguP3668][USACO17OPEN]Modern Art2(Link

現在你有一塊長為\(N\)的畫布,每次可以選擇一段連續的區間進行顏色填塗,新顏色會覆蓋舊顏色。每一次填塗都要耗費一天時間。在所有的填塗中每一種顏色只能用1次。求將畫布變為目標序列的最小天數。如果不能完成填塗那麼輸出\(-1\)

首先我們要知道填塗的方式以及什麼叫做填塗不合法。

Pic1

上面的這個方案明顯是合法的,我們先塗上“底色”\(Green\)然後再塗\(Red\)就好。

Pic2

上面的這個情況,你發現無論怎麼塗都是不合法。那麼我們找到了一個顯然的規律:有交叉的顏色就不合法。

於是問題變得簡單了,我們用一個棧直接記錄一下花費時間就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 100010 ;
const int MAXM = 100010 ;
int N, Line[MAXN], S[MAXN], S1[MAXN], Top, S2[MAXN], Sum ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

int main() {
    N = Read() ;
    for (int i = 1 ; i <= N ; i ++)  {
        Line[i] = Read() ; S2[Line[i]] = i ;
        if (! S1[Line[i]]) S1[Line[i]] = i ;
    }   S2[Line[N + 1]] = N + 1 ;
    for (int i = 0 ; i <= N + 1 ; i ++) {
        if (i == S1[Line[i]]) S[++ Top] = Line[i], Sum = max(Top, Sum) ;
        if (Line[i] != S[Top]) {
            printf("-1") ; return 0 ;
        }   if (i == S2[Line[i]]) Top -- ;
    }
    printf("%d", Sum) ;
}