CF1270B题解
题面
题目传送门
给出一个数列,要求找出一段连续的子数列满足这个子数列的最大值与最小值之差不小于其元素个数(子数列可以是原数列)。
即给定一个数组 $a$:$a_1,a_2,a_3\cdots a_n$,要找出两个下标 $l,r(l<r,l,r\in [1,n])$ 使得 $|a_r-a_l|\leqslant r-l+1$。
思路
首先,看到这题就想偷懒,于是就想到要是只用判断长度为 $2$ 的子串那多简单啊,可仔细一想,还真行!
那就要说我发现的一个结论了:有一个长度为 $n$ 的数组 $a$ 是合法的,至少有一个长度为 $2$ 的子序列也是合法的。
证明这个结论也很简单,其实就用反证法就行了:
假设有一个长度为 $n$ 的数组 $a$ 是合法的,但是 $a$ 的每一个长度为 $2$ 子序列都不合法。
那么,依假设,$|a_2-a_1|<2,|a_3-a_2|<2,\cdots,|a_n-a_{n-1}|<2$,
$\because a_i\in \mathbb{Z}(i\in[1,n])$,
$\therefore|a_2-a_1|\leqslant1,|a_3-a_2|\leqslant1,\cdots,|a_n-a_{n-1}|\leqslant1$,
$\therefore$ 数列最大值减数列最小值 $<n-1$,即数列不合法,与假设矛盾!
故有一个长度为 $n$ 的数组 $a$ 是合法的,至少有一个长度为 $2$ 的子序列也是合法的。
于是,只需判断长度为 $2$ 的子串即可。
总结
- 反证法。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[200005],T,n;
int main(){scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1; i<=n; i++) scanf("%d",&a[i]);bool ok=1;//判断是否有解 for(int i=2; i<=n; i++){if(abs(a[i]-a[i-1])>=2){//要是这个长度为2的子序列合法 ok=0;//有解printf("YES\n%d %d\n",i-1,i);break;}}if(ok) printf("NO\n");//无解则输出 NO}return 0;
}