E. Unique Array
E. Unique Array
You are given an integer array of length . A subarray of is one of its contiguous subsequences (i. e. an array for some integers and such that ). Let's call a subarray unique if there is an integer that occurs exactly once in the subarray.
You can perform the following operation any number of times (possibly zero): choose an element of the array and replace it with any integer.
Your task is to calculate the minimum number of aforementioned operation in order for all the subarrays of the array to be unique.
Input
The first line contains a single integer () — the number of test cases.
The first line of each test case contains a single integer ().
The second line contains integers ().
Additional constraint on the input: the sum of over all test cases doesn't exceed .
Output
For each test case, print a single integer — the minimum number of aforementioned operation in order for all the subarrays of the array to be unique.
Example
Input
4
3
2 1 2
4
4 4 4 4
5
3 1 2 1 2
5
1 3 2 1 2
Output
0
2
1
0
Note
In the second test case, you can replace the -st and the -rd element, for example, like this: .
In the third test case, you can replace the -th element, for example, like this: .
解题思路
参考的官方题解,做法挺难想到的。
首先如果要修改某个元素,显然应该修改成当前数组中不存在的数值,这样修改后,所有包含该元素的子数组必然是 unique 的。对此问题转换成了考虑所有不满足 unique 的子数组,最少需要修改多少个元素,使得这些子数组都至少包含一个被修改的元素。
这就是一个经典的贪心问题:区间选点。即给定若干个区间,问最少选择多少个点使得每个区间内至少包含一个选出的点。做法是先对所有区间按右端点从小到大排序,记上一次选择的点的位置为 (初始时置为 ),依次枚举每个区间 ,如果 ,则选择点 并更新 ,答案加 。
在本题中我们可以按照区间的右端点将不满足 unique 的子数组进行分类,依次遍历数组 中的每个元素并维护上一个被修改元素的下标 。当枚举到 ,找到非 unique 的子数组 的最大下标 ,如果 ,那么修改 并更新 。为什么不考虑非 unique 的子数组 呢?这是因为如果 ,则有 ,即所有以 为右端点的非 unique 子数组都包含了被修改的 。否则 ,我们必须要在 中选择一个元素 () 修改,此时所有以 为右端点的非 unique 子数组也都包含了被修改的 。
现在的问题是对于每个 ,如何快速找到上述提到的 ?暴力的做法就是从 往左枚举,并维护每个数值出现的次数,当发现到达某个位置时数值都出现了至少两次,那么这个位置就是 。我们可以用支持区间加和查询区间最小值的线段树来加快这个过程。首先我们用另外一种方式去模拟上述过程,开一个数组 ,对于 出现的每个数值,在 的该数值出现的最后一个位置处标记为 ,倒数第二个位置标记为 ,其他的位置标记为 。对 求后缀和,即 ,如果在 中存在某个 ,说明必然有 ,此时就要修改 。
不妨假设在枚举完 后维护出了 ,此时的 。现在枚举到 ,则需要将每个 更新成 。具体做法是找到数值 的倒数第 个位置 和倒数第 个位置 ,然后令 从 变成 ; 从 变成 ; 变成 。对应到 的更新就是让 都加上 ; 都加上 ; 都加上 。然后判断 中的最小值是否大于 。因此我们需要用线段树来维护这个 数组。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 5;
int a[N];
vector<int> p[N];
struct Node {
int l, r, mn, add;
}tr[N * 4];
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 0};
if (l != r) {
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
}
void pushdown(int u) {
if (tr[u].add) {
tr[u << 1].mn += tr[u].add;
tr[u << 1].add += tr[u].add;
tr[u << 1 | 1].mn += tr[u].add;
tr[u << 1 | 1].add += tr[u].add;
tr[u].add = 0;
}
}
void modify(int u, int l, int r, int c) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].mn += c;
tr[u].add += c;
}
else {
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, c);
if (r >= mid + 1) modify(u << 1 | 1, l, r, c);
tr[u].mn = min(tr[u << 1].mn, tr[u << 1 | 1].mn);
}
}
int query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u].mn;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (r <= mid) return query(u << 1, l, r);
if (l >= mid + 1) return query(u << 1 | 1, l, r);
return min(query(u << 1, l, r), query(u << 1 | 1, l, r));
}
void solve() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
p[i].clear();
}
build(1, 1, n);
int ret = 0;
for (int i = 1, j = 0; i <= n; i++) {
p[a[i]].push_back(i);
int sz = p[a[i]].size();
if (sz >= 3) modify(1, 1, p[a[i]][sz - 3], 1);
if (sz >= 2) modify(1, 1, p[a[i]][sz - 2], -2);
modify(1, 1, p[a[i]][sz - 1], 1);
if (!query(1, j + 1, i)) {
j = i;
ret++;
}
}
printf("%d\n", ret);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Educational Codeforces Round 165 Editorial:https://codeforces.com/blog/entry/129022
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18180900
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2023-05-08 G. Hits Different