杂题练习

发布时间 2023-11-03 17:32:25作者: mrsunss

stl

众所周知一般来说,随着社会经济的不断发展,stl越来越成为一款强大的工具。

著名cp选手i_wish_a_gilrfriend曾说过:stl,启动!

无敌山鸡王说:我在学习了算法近一年后才了解stl,这是我的巨大损失。

五星上将麦克阿瑟曾说过,如果上帝不让我使用stl,那我将用枪指向上帝。

下面是练习使用stl题单,如果能熟练并轻松切出说明你很会stl。

 

1.CFgym104172 L - Permutation Compression

题解

发现从大的往小的删,是优的。因为先删了小的,对大的没有影响;未删大的就删小的,对小的会有影响,限制可能增多。

于是我们考虑从大的开始删,然后就每次找到当前值$x$作为最大值的最长区间,设长度为$length$,然后贪心的找到$L$数组中一个$L_i \le length$,然后将这个值$x,L_i$分别从数组中删去。这个东西可以用树状数组和set维护。

查看代码

void Solve(int TIME) {
 
    int n, m, k;cin >> n >> m >> k;
    BIT tr(n + 1);
    set<int> del;for (int i = 1;i <= n;i++) del.insert(i);//待删元素
    set<int> limited;int last_dele = n + 1;//限制,上次删的元素
    limited.insert(0);limited.insert(n + 1);
    vi a(n + 1);for (int i = 1;i <= n;i++) cin >> a[i];
    vi b(m + 1);for (int i = 1;i <= m;i++) cin >> b[i], del.erase(b[i]);
    vi l(k + 1);for (int i = 1;i <= k;i++) cin >> l[i];
    multiset<int> set_L;for (int i = 1;i <= k;i++) set_L.insert(l[i]);
    vi pos(n + 1);for (int i = 1;i <= n;i++) pos[a[i]] = i;
    for (int i = 1;i < m;i++) {
        if (pos[b[i]] < pos[b[i + 1]]) continue;
        return cout << "NO" << endl, void();
    }
    for (auto it = del.rbegin();it != del.rend();it++) {
        auto val = *it;
        for (int i = last_dele - 1;i >= val + 1;i--) {
            limited.insert(pos[i]);
        }
        auto right_lim = *limited.upper_bound(pos[val]);
        auto left_lim = *prev(limited.upper_bound(pos[val]));
        int length = right_lim - left_lim - 1; length -= tr.query(left_lim + 1, right_lim - 1);
        auto find_l = set_L.upper_bound(length);if (find_l == set_L.begin()) return NO, void();
        set_L.erase(--find_l);
        tr.add(pos[val], 1);
        last_dele = val;
    }
    YES;
 
}