题目地址:
https://www.luogu.com.cn/problem/P3901
题目描述:
现有数列
A
1
,
A
2
,
…
,
A
N
A_1,A_2,\ldots,A_N
A1,A2,…,AN,
Q
Q
Q个询问
(
L
i
,
R
i
)
(L_i,R_i)
(Li,Ri),询问
A
L
i
,
A
L
i
+
1
,
…
,
A
R
i
A_{L_i} ,A_{L_i+1},\ldots,A_{R_i}
ALi,ALi+1,…,ARi是否互不相同。
输入格式:
第一行,两个整数
N
,
Q
N,Q
N,Q。
第二行,
N
N
N个整数
A
1
,
A
2
,
…
,
A
N
A_1, A_2, \ldots , A_N
A1,A2,…,AN。
接下来
Q
Q
Q行,每行两个整数
L
i
,
R
i
L_i,R_i
Li,Ri。
输出格式:
对每个询问输出一行,Yes
或No
。
数据范围:
对于
50
%
50\%
50%的数据,
N
,
Q
≤
1
0
3
N,Q \le 10^3
N,Q≤103。
对于
100
%
100\%
100%的数据,
1
≤
N
,
Q
≤
1
0
5
1 \le N,Q \le 10^5
1≤N,Q≤105,
1
≤
A
i
≤
N
1 \le A_i \le N
1≤Ai≤N,
1
≤
L
i
≤
R
i
≤
N
1 \le L_i \le R_i \le N
1≤Li≤Ri≤N。
可以用一个数组 c [ i ] c[i] c[i]记录 A i A_i Ai左边出现的最近的位置,然后令数组 f [ i ] = max j ≤ i c [ j ] f[i]=\max_{j\le i} c[j] f[i]=maxj≤ic[j],表示 A 1 , . . . , i A_{1,...,i} A1,...,i左边出现的位置的最大值。可以递推 f [ i ] = max { f [ i − 1 ] , c [ i ] } f[i]=\max\{f[i-1],c[i]\} f[i]=max{f[i−1],c[i]}。那么对于每个询问, A L , . . . , A R A_L,...,A_R AL,...,AR互不相同,当且仅当 max { c L , . . . , c R } < L \max\{c_L,...,c_R\}<L max{cL,...,cR}<L,而 max { c L , . . . , c R } < L ⇔ max { c 1 , . . . , c R } = f [ R ] < L \max\{c_L,...,c_R\}<L\Leftrightarrow \max\{c_1,...,c_R\}=f[R]<L max{cL,...,cR}<L⇔max{c1,...,cR}=f[R]<L所以直接询问 f [ R ] < L f[R]<L f[R]<L是否成立即可。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, q;
int close_left[N], last[N], far_left[N];
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
close_left[i] = last[x];
last[x] = i;
far_left[i] = max(close_left[i], far_left[i - 1]);
}
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
far_left[r] < l ? puts("Yes") : puts("No");
}
}
预处理时间复杂度 O ( N ) O(N) O(N),每次询问 O ( 1 ) O(1) O(1),空间复杂度 O ( N + max A ) O(N + \max A) O(N+maxA)。