1. 程式人生 > 其它 >CF1630C(區間覆蓋)

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;
}