CF1270B - Interesting Subarray | 思维

links

给出一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\) ,求一子段 \(a_l, a_{l + 1}, a_{l + 2}, \cdots, a_{r - 1}, a_r\) ,满足 \(\max\{a_l,\cdots,a_r\} - \min\{a_l,\cdots,a_r\} \geq r - l + 1\)。若有多个,输出任意一个子段的左右端点即可。若不存在,输出NO
\(n \leq 2 \times 10 ^ 5\)

虽然做出来了,但做复杂了。所以又没有完全做出来(

当时想的是直接把 \(\max - \min\) 的条件改成 \(a_r - a_l\) ,然后再找。因为最优的情况必然是一端为 \(\min\) 另一端为 \(\max\) 。然后忘记考虑 \(a_l - a_r\) 的情况还 WA 了一发。

后来讲题的时候,说先考虑相邻两个是否有合适的,如果有就有了。如果没有,说明相邻两个的差值不超过 \(1\) ,那么随着子段的延伸,\(\max - \min\) 永远追不上子段长度,就肯定是 NO 了。

很妙,可惜我错过了,很多事情,错过一次,就没有第二次了。

先从局部着手,考虑动态的变化。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
	using namespace std;
int main() {
	int T = 0;
	scanf("%d", &T);
	for (int G = 1; G <= T; G++) {
		int n = 0, lst = -1;
		int l = -1, r = -1;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			int a = 0;
			scanf("%d", &a);
			if (i >= 2 && abs(lst - a) >= 2) {
				l = i - 1, r = i;
			}
			lst = a;
		}
		if (l == -1) printf("NO\n");
		else printf("YES\n%d %d\n", l, r);
	}
	return 0;
} 
posted @ 2024-03-26 16:44  kcccn  阅读(10)  评论(0)    收藏  举报