qwq

CF467E 题解

题面

为方便起见,把数叫做颜色。把 \(a_i,a_j,a_k,a_w(a_i=a_k,a_j=a_w,i<j<k<w)\) 加入 \(b\) 中叫做一次加入。

注意到如果从左到右扫描时,某四个数符合要求,就可以直接加入,这样一定比把某种颜色留到后面用更优。

因为这四个数留到后面最多只能贡献给另外一次的加入。答案一定不优。

于是可以直接贪心。

考虑一次加入的四个数 \(x_1\ y_1\ x_2\ y_2(x_1=x_2,y_1=y_2)\),当扫描到 \(x_2\) 时,我们就可以给每个满足条件的 \(y_1\) 的颜色打上标记。

当扫描到的位置 \(p\) 的颜色被打上标记时,说明存在一次加入,且 \(y_2=a_p\)

哪些 \(y_1\) 满足条件呢?

设当前扫描到的位置为 \(i\)(令 \(x_2\) 的颜色为 \(a_i\))。

考虑维护一个栈 \(S\) 作为可能的 \(y_1\) 集合,再维护 \(cnt_j\) 表示 \(k\in{S},a_k=j\)\(k\) 的个数。

如果栈顶的颜色不为 \(a_i\),且 \(cnt_{a_i}\geq 1\)(存在 \(x_1\)),则有可能为 \(y_1\)

如果栈顶颜色等于 \(a_i\),说明可能 \(x_1=y_1=x_2=y_2\),那么当且仅当 \(cnt_{a_i}>1\)(存在两个相同颜色,同时作为 \(x_1,y_1\))。

否则不可能。

如果栈顶可能成为 \(y_1\),就可以弹出了。否则结束判断,更新 \(cnt_{a_i}\),扫描下一个。

如果扫描到被打上标记的,那么加入答案,并且前面的标记全部作废。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 5e5 + 5;
int n, a[N];

unordered_map<int, int> pre, cnt;

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    stack<int> s;
    vector<int> ans;
    for(int i = 1; i <= n; i ++)
    {
        if(pre.count(a[i]))
        {
            ans.push_back(pre[a[i]]);
            ans.push_back(a[i]);
            ans.push_back(pre[a[i]]);
            ans.push_back(a[i]);
            pre.clear(), cnt.clear();
            continue;
        }
        while(s.size() && (cnt[a[i]] > 1 || (cnt[a[i]] == 1 && s.top() != a[i])))
        {
            pre[s.top()] = a[i];
            cnt[s.top()] --;
            s.pop();
        }
        cnt[a[i]] ++;
        s.push(a[i]);
    }
    cout << ans.size() << "\n";
    for(int i : ans) cout << i << " ";

    return 0;
}

作者:adam01

出处:https://www.cnblogs.com/adam01/p/18323792

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   adam01  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up light_mode palette
选择主题