码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForce 1454 F. Array Partition

时间:2020-12-03 12:29:41      阅读:15      评论:0      收藏:0      [点我收藏+]

标签:href   ack   个数   alt   一个   space   ref   ace   c++   

题目链接

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;
}


CodeForce 1454 F. Array Partition

标签:href   ack   个数   alt   一个   space   ref   ace   c++   

原文地址:https://www.cnblogs.com/Carered/p/14057228.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!