http://acm.hdu.edu.cn/showproblem.php?pid=4512
题目意思:给定一个序列,求最长回文子序列,满足从中点到两端依次递减。
先看LCIS最长公共上升子序列。
dp[i]表示当前以下标i结束的最长公共上升子序列。
我们让第一个序列为原序列,第二个序列为原系列的反向。
则,也就是说,第二个序列的顺序为原序列的下标[n-1,0],设为j
当j枚举到k时,对于dp[0] ~ dp[k-1],都可以得到原序列的一个长度为2*dp[i]的题目要求的子序列。
可是对于,dp[k],我们怎么判断此时,两个序列是否存在交集呢?假如存在交集,此时题目要求的子序列长度为2*dp[k] - 1
这样考虑,假如此时的序列没有交集,则此时两个序列的最长公共上升子序列,在序列二中的起始坐标必然不是k
那么它必然在j=[k+1,n-1]的时候已经出现过,并以dp[k]*2更新过ans
也就是说根本不用考虑嘛。。。直接将用dp[k]*2-1更新ans,答案并不会有错。
代码:
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int n,ans,a[201],dp[201]; 5 inline void Max(int &a,const int b){if(b>a) a=b;} 6 int main() 7 { 8 int T; 9 scanf("%d",&T); 10 while(T--){ 11 scanf("%d",&n); 12 memset(dp,0,sizeof dp); 13 for(int i=0;i<n;i++) scanf("%d",a+i); 14 ans=1; 15 for(int k=n-1;k>=0;k--){ 16 int x=a[k],mx=0; 17 for(int i=0;i<=k;i++){ 18 if(a[i]<x) Max(mx,dp[i]); 19 else if(a[i]==x) dp[i]=mx+1; 20 if(i<k) Max(ans,dp[i]*2); 21 else Max(ans,dp[i]*2-1); 22 } 23 } 24 printf("%d\n",ans); 25 } 26 return 0; 27 }