题目:
(以前也写过一次原题,做法有些不同于他人,写来记录一下)
做法1:
先求一堆单调上升的块,然后枚举每一个块,看能不能和其相邻的块相接得到更大的块。
做法2:
定义dp[ i ][ 0/1/2 ] 表示递推到第i个数,0表示到 i 没有使用过上升或下降的机会,1表示使用过,且不是前一个使用的,2表示使用过,且是前一个使用的。再用一个tmp数组保存一下改变后的值。
为什么不直接定义0/1呢?
求dp[ i ][ 1 ]的时候,会发现比较大小时,不确定是用tmp[ i-1 ]还是a[ i-1 ],即不知道那个被改变的数的位置,所以多加一维2。
转移就很好想啦~~
记得正反都做一次
#include<bits/stdc++.h> using namespace std; #define N 100005 int a[N],dp[N][5],tmp[N],n; int read() { int x=0,fl=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar(); return x*fl; } int main() { freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); n=read(); for(int i=1;i<=n;++i) a[i]=read(),tmp[i]=a[i]; a[0]=-(0x7f7f7f); int ans=0; for(int i=1;i<=n;++i){ if(a[i-1]<a[i]) dp[i][0]=dp[i-1][0]+1; else dp[i][0]=1; if(a[i-1]<a[i]) dp[i][1]=max(dp[i][1],dp[i-1][1]+1); if(tmp[i-1]<a[i]) dp[i][1]=max(dp[i][1],dp[i-1][2]+1); if(!dp[i][1]) dp[i][1]=1; dp[i][2]=dp[i-1][0]+1 , tmp[i]=a[i-1]+1;//这样能留给后面的更多机会接上 ans=max(ans,dp[i][0]); ans=max(ans,dp[i][1]); ans=max(ans,dp[i][2]); }//刚刚只考虑了tmp为前一个+1的情况 但其实还可能是后一个-1 所以反着再做一次 for(int i=1;i<=n;i++) tmp[i]=a[i]; memset(dp,0,sizeof(dp)); a[n+1]=0x7f7f7f; for(int i=n;i>=1;--i){ if(a[i]<a[i+1]) dp[i][0]=dp[i+1][0]+1; else dp[i][0]=1; if(a[i]<a[i+1]) dp[i][1]=max(dp[i][1],dp[i+1][1]+1); if(a[i]<tmp[i+1]) dp[i][1]=max(dp[i][1],dp[i+1][2]+1); if(!dp[i][1]) dp[i][1]=1; dp[i][2]=dp[i+1][0]+1 , tmp[i]=a[i+1]-1; ans=max(ans,dp[i][0]); ans=max(ans,dp[i][1]); ans=max(ans,dp[i][2]); } printf("%d ",ans); return 0; } /* 6 7 2 3 1 5 6 4 6 7 2 3 5 3 4 -5 6 0 15 8 2 3 4 5 7 2 3 4 5 2 3 4 5 6 */