zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    
  • 相关阅读:
    微信小程序开发---各代码文件简介
    LeetCode71. 简化路径
    LeetCode70. 爬楼梯
    LeetCode69. x 的平方根
    LeetCode68. 文本左右对齐
    LeetCode剑指 Offer 09. 用两个栈实现队列
    LeetCode67. 二进制求和
    LeetCode66. 加一
    LeetCode65. 有效数字
    LeetCode64. 最小路径和
  • 原文地址:https://www.cnblogs.com/Carered/p/14057228.html
Copyright © 2011-2022 走看看