时间复杂度:O(mlogm)
区间覆盖问题
给定n个小区间和一个范围[a, b],选择尽量少的区间,使得[a, b]能够被完全覆盖。
解法:贪心
如果有区间x和y,x包含了y,显然选择x这个大区间更好。
因此考虑对每个区间按左端点升序排序,从第一个小区间开始选择,每次选择区间左端点在目标区间内且右端点尽可能大的区间。每次选择区间后更新目标区间(左端点更新为选中区间的右端点+1)。
排序开销:O(nlogn)
选区间开销:O(n)
总时间复杂度:O(nlogn)
区间预处理
显然,本题没有明说各个小区间,因此需要预处理出小区间。
我们可以把m个请求服务器看成[0,m-1]的区间。
每个代理服务器在需要切换之前(后)看成小区间。
如请求服务器顺序为ABBA,那么A对应的小区间有[1,2],B对应的小区间有[0,0]、[3,3]
源码
//
// Created by Zed on 2024/1/22.
//
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <map>
using namespace std;
const int MAXN = 1e3 + 100;
struct Interval {
int a, b;
bool operator<(const Interval interval) {
if (a != interval.a) {
return a < interval.a;
}
return b > interval.b;
}
} intervals[MAXN];
int main() {
int n, m;
while (cin >> n) {
map<string, int> dict;//维护上一次IP出现的下标
for (int i = 0; i < n; ++i) {
string tmp;
cin >> tmp;
dict[tmp] = -1;
}
int cnt = 0;//区间数
cin >> m;
for (int i = 0; i < m; ++i) {
string tmp;
cin >> tmp;
if (dict.count(tmp)) {
if (i - 1 >= dict[tmp] + 1) {
intervals[cnt].a = dict[tmp] + 1;
intervals[cnt].b = i - 1;//不包含端点
cnt++;
}
dict[tmp] = i;
}
}
for (const auto &item: dict) {
if (m - 1 >= item.second + 1) {
intervals[cnt].a = item.second + 1;
intervals[cnt].b = m - 1;//不包含端点
cnt++;
}
}
sort(intervals, intervals + cnt);
int ans = -1;
int l = 0;
int j = 0;
while (l <= m - 1 && j < cnt) {
if (intervals[j].a > l) {
ans = -1;
break;
}
int tmp_l = l;
while (j < cnt && intervals[j].a <= l) {
tmp_l = max(intervals[j].b + 1, tmp_l);
j++;
}
l = tmp_l;
ans++;
}
cout << ans << endl;
}
}

京公网安备 11010502036488号