Codeforces Round #227 (Div. 2) E. George and Cards 线段树+set

本文介绍了一道关于从卡片序列中移除特定数量卡片的问题,旨在最大化移除过程中的得分。通过采用贪心策略和数据结构优化(如使用set和线段树),实现了高效的解决方案。

题目链接:

题目

E. George and Cards
time limit per test:2 seconds
memory limit per test:256 megabytes

问题描述

George is a cat, so he loves playing very much.

Vitaly put n cards in a row in front of George. Each card has one integer written on it. All cards had distinct numbers written on them. Let's number the cards from the left to the right with integers from 1 to n. Then the i-th card from the left contains number pi (1 ≤ pi ≤ n).

Vitaly wants the row to have exactly k cards left. He also wants the i-th card from left to have number bi written on it. Vitaly gave a task to George, to get the required sequence of cards using the remove operation n - k times.

In one remove operation George can choose w (1 ≤ w; w is not greater than the current number of cards in the row) contiguous cards (contiguous subsegment of cards). Let's denote the numbers written on these card as x1, x2, ..., xw (from the left to the right). After that, George can remove the card xi, such that xi ≤ xj for each j (1 ≤ j ≤ w). After the described operation George gets w pieces of sausage.

George wondered: what maximum number of pieces of sausage will he get in total if he reaches his goal and acts optimally well? Help George, find an answer to his question!

输入

The first line contains integers n and k (1 ≤ k ≤ n ≤ 106) — the initial and the final number of cards.

The second line contains n distinct space-separated integers p1, p2, ..., pn (1 ≤ pi ≤ n) — the initial row of cards.

The third line contains k space-separated integers b1, b2, ..., bk — the row of cards that you need to get. It is guaranteed that it's possible to obtain the given row by using the remove operation for n - k times.

输出

Print a single integer — the maximum number of pieces of sausage that George can get if he acts optimally well.

样例

input
3 2
2 1 3
1 3

output
1

input
10 5
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10

output
30

题意

给你一个长度为n的原始序列和一个长度为k子序列,要你把不属于这个子序列的数都删了,你可以选择的操作是每次选连续的w个数,然后删除最小的那个,并且你能够获得w的贡献值,问你如何操作n-k次使贡献值的和最大。

题解

只要我们按序列的值递增来做,并且每次贪心取最大的区间,就能得到最优,一开始我用线段树维护sum和min,在每次操作时用二分+区间min找到左右界,用sum统计区间内还存在的数的和。复杂度O(nlogn+n(logn)^2)第八组数据就t了。(orz)
正解是一开始就用一个set只维护那些比当前数小的并且最后一定会保留下来的数(不会保留下来的,比当前数小的数都已经删除了,所以根本不要放到set里面,这样子做的话每次找x的前驱后继就可以做完了,再加一个线段树或树状数组维护一下区间和就可以了,时间复杂度只有O(nlogn)。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<set>
#define X first
#define Y second
#define M l+(r-l)/2
#define lson (o<<1)
#define rson ((o<<1)|1)
using namespace std;

const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
typedef __int64 LL;

int minv[maxn << 2];
LL sumv[maxn << 2];
int used[maxn],id[maxn];
int n, k;
set<int> st;

int _p, _v;
void update(int o, int l, int r) {
    if (l == r) {
        sumv[o] = _v;
    }
    else {
        if (_p <= M) update(lson, l, M);
        else update(rson, M + 1, r);
        minv[o] = min(minv[lson], minv[rson]);
        sumv[o] = sumv[lson] + sumv[rson];
    }
}

int ql, qr;
LL _sum;
void query(int o, int l, int r) {
    if (ql <= l&&r <= qr) {
        _sum += sumv[o];
    }
    else {
        if (ql <= M) query(lson, l, M);
        if (qr > M) query(rson, M + 1, r);
    }
}

int main() {
    memset(used, 0, sizeof(used));
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        int x; scanf("%d", &x);
        id[x] = i;
        _p = i; _v = 1;
        update(1, 1, n);
    }
    for (int i = 1; i <= k; i++) {
        int x;  scanf("%d",&x);
        used[x] = 1;
    }
    LL ans = 0;
    st.insert(0);
    st.insert(n + 1);
    for (int i = 1; i <= n; i++) {
        if (!used[i]) {
            set<int>::iterator it = st.upper_bound(id[i]);
            qr = *it - 1; ql = *(--it) + 1;
            _sum = 0;
            query(1, 1, n);
            ans += _sum;
            _p = id[i], _v = 0;
            update(1, 1, n);
        }
        else {
            st.insert(id[i]);
        }
    }
    printf("%I64d\n", ans);
    return 0;
}

乱七八糟:

这道题和之前做过的用线段树来维护一个元素的名次的动态查询点这里有异曲同工之妙,都利用了数本身的有序性来排除其他干扰的元素。 这道题也体现了离线处理的巧妙,比如说排个序啥的是吧。

转载于:https://www.cnblogs.com/fenice/p/5678015.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值