1. 程式人生 > >洛谷P1155 【NOIP2008】雙棧排序

洛谷P1155 【NOIP2008】雙棧排序

題目連結

題解

這題有點神啊。。
我們仔細觀察一下,發現兩個棧內元素必須為降序
那麼有結論 如果有\(i < j < k\)\(a[k] < a[i] < a[j]\)\(i\)\(j\)不能存在於同一個棧
證明:
因為棧內元素必須降序,
那麼加入\(a[j]\)時一定彈出了\(a[i]\),而又因為從小到大排序,
所以\(a[k]\)應該在\(a[i]\)前彈出,故結論正確。
證畢!

因為是兩個棧

那麼我們可以搞一個二分圖染色

最後貪心模擬一遍

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N], s1[N], s2[N], Min[N], t1, t2, ans[N<<1], len, n;
bool G[N][N], vis[N];
int z[N];
void dfs(int x, int c) {
    vis[x] = 1; z[x] = c;
    for (int i = 1; i <= n; i++) {
        if (!G[x][i]) continue;
        if (!vis[i])
            dfs(i, c^1);
        else if (c == z[i]) {
            printf("0\n");
            exit(0);
        }
    }
    return ;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    Min[n+1] = 2147483647;
    for (int i = n; i >= 1; i--)
        Min[i] = min(Min[i+1], a[i]);
    for (int i = 1; i < n; i++)
        for (int j = i+1; j <= n; j++)
            if (Min[j+1] < a[i] && a[i] < a[j])
                G[i][j] = G[j][i] = 1;
    for (int i = 1; i <= n; i++)
        if (!vis[i])
            dfs(i, 0);
    int now = 1;
    for (int i = 1; i <= n; i++) {
        if (!z[i]) {
            while (s1[t1] == now) {
                now++;
                t1--;
                ans[++len] = 1;
            }
            s1[++t1] = a[i];
            len++;
        }
        else {
            while (s1[t1] == now) {
                now++;
                t1--;
                ans[++len] = 1;
            }
            while (s2[t2] == now) {
                now++;
                t2--;
                ans[++len] = 3;
            }
            s2[++t2] = a[i];
            ans[++len] = 2;
        }
    }
    while (now <= n) {
        if (s1[t1] == now) ans[++len] = 1, t1--;
        else ans[++len] = 3, t2--;
        now++;
    }
    for (int i = 1; i <= len; i++) printf("%c ", ans[i]+'a');   
    return 0;
}