CF446A DZY Loves Sequences
CF446A DZY Loves Sequences
题目描述
给一个长度为n的序列a,定义ai,ai+1,ai+2....aj(1<=i<=j<=n)的长度为j-i+1,你可以最多更改一个数字,求最长的严格递增子段
输入格式
第一行包含n(1<=n<=105)表示序列长度。下一行包含a1到an(1<=ai<=109)
输出格式
输出最长的递增子段的长度
说明
你可以选择a2,a3,a4,a5,a6并且将a4更改为4
题解:
一开始的想法是按正常思路DP,设状态为dp[i] [0/1/2]表示前i位没修改,修改了但是不是i,修改了i的最长长度。但是这样的DP是错误的,因为虽然我们把修改的位设出来了,但是我们并不知道它最终被修改成了什么,也就是说,假如这个数被修改使得其符合了前面的那部分,但是你并不保证它改完之后也符合后面的部分。
所以这个状态是错的,根据它的错误理由,我们想到了正确的设状态方式:\(l[i],r[i]\)分别表示以i结尾、以i开头的最长严格递增子段的长度。
初值是\(l[1]=r[n]=1\),也就需要正着来一遍,反着来一遍。先不用考虑修改,修改是在统计答案的转移时做到的。在答案转移时,把两侧的序列合法地拼起来(有条件转移),就统计出了答案。
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int a[maxn],l[maxn],r[maxn];
int n,ans;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
l[1]=r[n]=1;
for(int i=2;i<=n;i++)
if(a[i-1]<a[i])
l[i]=l[i-1]+1;
else
l[i]=1;
for(int i=n-1;i;i--)
if(a[i]<a[i+1])
r[i]=r[i+1]+1;
else
r[i]=1;
for(int i=1;i<=n;i++)
{
ans=max(ans,max(l[i-1]+1,r[i+1]+1));
if(a[i-1]+1<a[i+1])
ans=max(ans,l[i-1]+1+r[i+1]);
}
printf("%d\n",ans);
return 0;
}