这道题一开始思路就是把线段分成两半,左边求上升右边求下降,然后果断wa,因为没有好好读题,上升子序列最后一位必须是下降子序列第一位,这就很难受了,但是仔细分析一下不难发现,dp[i]表达的是以a[i]结尾的最长子序列
例如:
求 1 3 2 4 5 的最长上升子序列
模拟dp过程应该有
dp[1] = 1, dp[2] = 2, dp[3] = 2, dp[4] = 3, dp[5] = 4,其中dp[2]就是以2结尾的最长上升子序列 为 1 2,长度为2
推广一下,我们可以保证每一个dp序列的最后一位是谁,但是无法保证第一位是谁
因此对于下降子序列,我们无法保证其第一位的情况下,只能将其倒叙,之前的下降子序列第一位对应着应该变成上升子序列的最后一位,整个过程变成了求两个最长上升子序列的问题,很奇妙
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
int main()
{
int a[1005];
int b[1005];
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i ++){
scanf("%d",&a[i]);
b[n - i + 1] = a[i];
}
int dp1[1005], dp2[1005];
for(int i = 1; i <= n; i ++)
dp1[i] = dp2[i] = 1;
for(int i = 2; i <= n; i ++)
for(int j = 1; j < i; j ++)
if(a[i] > a[j])
dp1[i] = max(dp1[i], dp1[j] + 1);
for(int i = 2; i <= n; i ++)
for(int j = 1; j < i; j ++)
if(b[i] > b[j])
dp2[i] = max(dp2[i], dp2[j] + 1);
int maxy = 0;
for(int i = 1; i <= n; i ++)
{
maxy = max(maxy, dp1[i] + dp2[n - i + 1] - 1);
}
printf("%d\n",maxy);
return 0;
}