题目: AcWing 1490. 最长上升子串
给出一个长度为 n 的由正整数构成的序列,你需要从中删除一个正整数,很显然你有很多种删除方式,你需要对删除这个正整数以后的序列求其最长上升子串,请问在所有删除方案中,最长的上升子串长度是多少。
这里给出最长上升子串的定义:即对于序列中连续的若干个正整数,满足 ai+1>ai,则称这连续的若干个整数构成的子串为上升子串,在所有的上升子串中,长度最长的称为最长上升子串。
输入格式
输入第一行仅包含一个正整数 n,表示给出的序列的长度。
接下来一行有 n 个正整数,即这个序列,中间用空格隔开。
输出格式
输出仅包含一个正整数,即删除一个数字之后的最长上升子串长度。
数据范围
1≤n≤105,
1≤ai≤105
输入样例:
5
2 1 3 2 5
输出样例:
3
题目分析:
因为数据范围在105,所以时间复杂度保证在O(n),O(logn)之内。
我们可以假设枚举删除每个点
假设删除i点,如果i点前面的最长上升子串的最大值小于右边最长上升子串的最小值,则就可以将它们相加。如果不小于我们就求左右两边最大值。
所以根据这个方法我们可以先预处理出以i为结束的最大上升子串的所有值,和以i为开始的最大上升子串的所有值。
最后根据删除点两边值判断。
时间复杂度: 3个for循环 O(n)
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100010;
int n;
int a[N],f[N],g[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
// 预处理f[i]:以i为结束的最大上升子串
for(int i=1;i<=n;i++)
if(a[i]>a[i-1])f[i]=f[i-1]+1;
else f[i]=1;
// 预处理g[i]:以i为开始的最大上升子串
for(int i=n;i>=0;i--)
if(a[i]<a[i+1])g[i]=g[i+1]+1;
else g[i]=1;
int res=0;
for(int i=1;i<=n;i++)
if(a[i-1]<a[i+1])res=max(res,f[i-1]+g[i+1]);
else res=max(res,max(f[i-1],g[i+1]));
cout<<res<<endl;
return 0;
}