简述题意
给定 n,l,r(1<l≤r<n) 和长度为 n 的正整数数列 a(1≤ai≤106)。一个数对 (i,j) 合法,当且仅当:
- 1≤i<l≤r<j≤n。
- 不存在 i′,j′ 使得 ai=ai′,aj=aj′ 且 i=i′∨j=j′。
- ai=aj。
找出可能的最小 j−i+1。1≤n≤106。
分析
对于上面的第二个条件,我们这么转化:(可证明正确性)
- 不存在 i′<j,i′=i,ai=ai′。
- 不存在 j′>i,j′=j,aj=aj′。
它意味着:
- j 在 ai 的头两次出现之间。
- i 在 aj 的末两次出现之间。
- i 是 ai 的第一次出现。
- j 是 aj 的最后一次出现。
感性地理解,也就是这样的一对 (ai,aj)=(x,y),分布形如 {y,…,y,x,y,x,…,x}。其中唯一的一组 (x,y) 就是 (i,j) 位了。
那么,我们枚举 i<l,只看所有末两次出现在 i 两侧的 aj(j>r),然后检测这个条件下最小的 j 是否在 ai 的头两次出现之间。而这里的 j 可以逐个预处理,然后枚举的时候做一个前缀 min。
时间、空间复杂度均为 O(n)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <bits/stdc++.h> using namespace std;
const int MXN = 1000005; int N, L, R, arr[MXN]; int fir[MXN], fir2[MXN], lst[MXN], lst2[MXN], mnr[MXN], cmr, ans;
int main() { cin >> N >> L >> R; for (int i(0); i != MXN; ++i) fir[i] = fir2[i] = N + 1; mnr[0] = N + 1; for (int i(1); i <= N; ++i) { cin >> arr[i]; lst2[arr[i]] = lst[arr[i]]; lst[arr[i]] = i; if (fir[arr[i]] == N + 1) fir[arr[i]] = i; else if (fir2[arr[i]] == N + 1) fir2[arr[i]] = i; mnr[i] = N + 1; } for (int i(R + 1); i <= N; ++i) { if (i == lst[arr[i]]) mnr[lst2[arr[i]]] = min(mnr[lst2[arr[i]]], i); } cmr = mnr[0]; ans = N + 1; for (int i(1); i < L; ++i) { if (i == fir[arr[i]] && cmr < fir2[arr[i]]) ans = min(ans, cmr - i + 1); cmr = min(cmr, mnr[i]); } cout << (ans == N + 1 ? -1 : ans) << endl; return 0; }
|