1. 程式人生 > 實用技巧 >CodeForce 1454 F. Array Partition

CodeForce 1454 F. Array Partition

題目連結

https://codeforces.com/problemset/problem/1454/F

題意

把一段長度為\(n\)的區間分成三段, 每段長度不為\(0\), 要求第一段區間的最大值等於第三段區間的最大值等於中間區間的最小值。輸出是否能劃分並輸出方案。

思路

可以列舉所有可能的答案, 那麼對於每一種答案,他的出現次數必定大於\(3\)
我們可以用單調棧維護一下每個數左右的最大值/最小值的位置,並且統計每個數出現的位置(需要事先離散化一下).
假設當前答案為\(x\), 那麼 \(x\) 第一次出現的位置左邊必須沒有比它大的數, 最後一次右邊同理, 那麼剩下中間出現的位置我們進行列舉。
中間出現的\(x\)

作為最小值時離它左右倆邊最近的最大值位置這段範圍就是這個最小值控制的區間,只需要判斷這個區間和第一次和最後一次出現位置控制的區間是否都有交集即可。

AC程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 50;
int ind[maxn], len;
inline int getid(const int &val){
    return lower_bound(ind + 1, ind + len + 1, val) - ind;
}
int getlen(int a[], int n){
    for(int i = 0;i <= n;i++){
        ind[i] = a[i];
    }
    sort(ind + 1, ind + n + 1);
    return unique(ind + 1, ind + n + 1) - ind - 1;
}
int st[maxn], Lmax[maxn], Rmax[maxn], Lmin[maxn], Rmin[maxn];
void getLmax(int a[], int n){//左邊第一個大於a[i]的數
    int cnt = 0;
    st[0] = 0;
    for(int i = 1;i <= n;i++){
        while(cnt && a[i] >= a[st[cnt]]) cnt--;
        Lmax[i] = st[cnt];
        st[++cnt] = i;
    }
}
void getRmax(int a[], int n){//右邊第一個大於a[i]的數
    int cnt = 0;
    st[0] = n + 1;
    for(int i = n;i >= 1;i--){
        while(cnt && a[i] >= a[st[cnt]]) cnt--;
        Rmax[i] = st[cnt];
        st[++cnt] = i;
    }
}
void getLmin(int a[], int n){//左邊第一個小於a[i]的數
    int cnt = 0;
    st[0] = 0;
    for(int i = 1;i <= n;i++){
        while(cnt && a[i] <= a[st[cnt]]) cnt--;
        Lmin[i] = st[cnt];
        st[++cnt] = i;
    }
}
void getRmin(int a[], int n){//右邊第一個小於a[i]的數
    int cnt = 0;
    st[0] = n + 1;
    for(int i = n;i >= 1;i--){
        while(cnt && a[i] <= a[st[cnt]]) cnt--;
        Rmin[i] = st[cnt];
        st[++cnt] = i;
    }
}
int a[maxn];
vector<int> v[maxn];
int main()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        for(int i = 1;i <= n;i++){
            cin >> a[i];
            v[i].clear();
        }
        len = getlen(a, n);
        for(int i = 1;i <= n;i++) a[i] = getid(a[i]);
        getLmax(a, n);
        getRmax(a, n);
        getLmin(a, n);
        getRmin(a, n);
        for(int i = 1;i <= n;i++){
            v[a[i]].push_back(i);
        }
        int ok = 0;
        for(int i = 1;i <= n;i++){
            int m = v[i].size();
            if(m < 3) continue;
            if(Lmax[v[i][0]] == 0 && Rmax[v[i][m - 1]] == n + 1){
                for(int j = 1;j < m - 1;j++){
                    int pos = v[i][j];
                    if(Lmin[pos] + 1 <= Rmax[v[i][0]] && Rmin[pos] - 1 >= Lmax[v[i][m - 1]]){
                        ok = 1;
                        cout << "YES" << endl;
                        int ansl = min(pos - 1, Rmax[v[i][0]] - 1);
                        int ansr = n - max(pos + 1, Lmax[v[i][m - 1]] + 1) + 1;
                        cout << ansl << " " << n - ansl - ansr << " " << ansr <<endl;
                        break;
                    }
                }
                if(ok) break;
            }
        }
        if(!ok) cout << "NO" << endl;
    }
    return 0;
}