题意:给定一个序列A,要在这个序列A里面找到一个连续子串,使得这个子串可以仅将其中某个元素修改为任意值然后得到一个严格单调递增的序列,问这样的子串最长是多少。
假设修改了某个值A[i]可以得到一个严格单调递增的序列,那么有三种情况:
1、令A[i]比A[i-1]大,然后求出从A[i-1]向左延伸的最长长度;
2、令A[i]比A[i+1]小,然后求出A[i+1]向右延伸的最长长度;
3、同时使得A[i-1]<A[i]<A[i+1],这个的前提条件是A[i+1]-A[i-1]>1,然后求出左右的延伸的最长长度;
其中求1和2是在3的条件不成立的情况下,3成立的话1和2不会比3优;
最后三种情况求最大值,然后加1(A[i]本身还没算进去),那么就是修改A[i]可以达到的最大值,然后枚举一遍A[i]求最大值即可。
关于左右延伸的长度,可以先通过预处理前后各扫一遍得到。
总复杂度O(N)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100001;
int n, a[N];
int f[N], g[N], ans;
//f代表向左边延伸的长度,g代表向右延伸的长度。
int main(){
while(~scanf("%d", &n)){
for(int i=0; i<n; i++){
scanf("%d", a+i);
if(i){
if(a[i]>a[i-1]) f[i]=f[i-1]+1;
else f[i] = 1;
}
else f[i] = 1;
}
if(n==1){
puts("1");
continue;
}
g[n-1] = 1;
for(int i=n-2; i>=0; i--){
if(f[i]<f[i+1]) g[i] = g[i+1]+1;
else g[i] = 1;
}
ans = max(g[1], f[n-2])+1;
for(int i=1; i<n-1; i++){
if(a[i+1]-a[i-1]>1){
ans = max(ans, f[i-1]+g[i+1]+1);
}
else{
ans = max(ans, f[i-1]+1);
ans = max(ans, g[i+1]+1);
}
}
printf("%d\n", ans);
}
return 0;
}