CF1630C(区间覆盖)

传送带:CF1630C

题意

给定 \(n\) 个元素,第 \(i\) 个元素有一个值 \(a_i\) 和一个颜色 \(c_i\), 给定 \(a_i\) 的值 \(c_i\) 的值为 \(0\), 可以执行无限次如下操作,每次选择满足 \(1 \leq i < j < k \leq n, c_i = c_j = c_k = 0\)\(a_i = a_k\) 的三个位置,然后将 \(s_j\) 变成 \(1\) , 求 \(\sum_{i = 1}^n c_i\) 的最大值。

分析

  • 贪心的考虑问题,对于每一个数 \(i\) 我们只需考虑首次出现和最后一次出现的位置,可以使整体的结果最大。
  • 针对以上各个数构成的区间,如果一个区间完全包含另一个区间(显然不会存在两个区间共享一个个端点),那么可以舍弃掉小区间。
  • 问题就转化为针对每个内部存在交集的区间的处理。

将由前面的分析提取出的区间排序后,我们考虑如何让答案更优。对于每个可以合成一个区间的区间段的两端的端点,显然是不能计算在内的,而其中的非端点一定能修改为 \(1\),除此之外的区间如果进行题面中的操作,必然有一个端点最终不能被计算在内。可以发现答案为:区间段长度-剩余区间个数-1。也就是说要保留最少的区间个数。

具体地方法为:可以采取扫描线的方法,初始的值为 \(0\) ,每次对比时,将下一个区间的左边界 \(l\) 与扫描线的值 \(val\) 比较,如果 \(l\leq val\) 的话,相当于当前的区间被下一个区间代替后,结果更优,否则当前的必须保留。

code

#include <bits/stdc++.h>

using namespace std;

using pii = pair<int, int>;

const int N = 2e5 + 10;

int n;
int a[N], cnt, l[N], r[N];

set<pii>st; //用set自动排序
vector<pii>v;

// 对当前的区间段计算答案
int res() {
    int len= v.back().second - v.front().first + 1; //区间总长度
    int cnt = 1; 	//c_i 不能改成 1 的位置的数量
    int vr = 0; 	//扫描线
    int sz = v.size();
    for (int i = 0; i < sz; ++i) {
        if (i == sz - 1 || v[i + 1].first > vr) { //最后一个区间的右端点要特判
            cnt++;
            vr = v[i].second;
        }
    }
    return len - cnt;
}

void slove() {
	cin >> n;
	for (int i = 1; i <= n; i++)  {
		cin >> a[i];
		if (!l[a[i]]) l[a[i]] = i;
		else r[a[i]] = i;
	}
	for (int i = 1; i <= n; i++) {
		if (r[i] > l[i]) st.emplace(l[i], r[i]);
	}
	if (st.empty()) {cout << 0 << '\n'; return; }
	int ans = 0;
	for (auto [x, y] : st) {
		if (v.empty()) { v.emplace_back(x, y); } 
		else if (v.back().second < x) { // 相邻两个区间不相交 计算上一个区间段的值
			ans += res();
			v.clear();
			v.emplace_back(x, y);
		} 
		else if (v.back().second < y) v.emplace_back(x, y);//与上一个相交
	}
	ans += res();
	cout << ans << '\n';
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
    int T;
    T = 1;
    while (T--) {
        slove();
    }
    return 0;
}
posted @ 2022-04-02 16:41  circletime  阅读(70)  评论(0)    收藏  举报