1 /*hud4512 2 dp[i]表示当前以下标i结束的最长公共上升子序列。 3 4 我们让第一个序列为原序列,第二个序列为原系列的反向。 5 6 则,也就是说,第二个序列的顺序为原序列的下标[n-1,0],设为j 7 8 当j枚举到k时,对于dp[0] ~ dp[k-1],都可以得到原序列的一个长度为2*dp[i]的题目要求的子序列。 9 10 可是对于,dp[k],我们怎么判断此时,两个序列是否存在交集呢?假如存在交集,此时题目要求的子序列长度为2*dp[k] - 1 11 12 这样考虑,假如此时的序列没有交集,则此时两个序列的最长公共上升子序列,在序列二中的起始坐标必然不是k 13 14 那么它必然在j=[k+1,n-1]的时候已经出现过,并以dp[k]*2更新过ans 15 16 也就是说根本不用考虑嘛。。。直接将用dp[k]*2-1更新ans,答案并不会有错 17 18 PS:原序列和反序列的公共部分不一定都是回文,你所找的最长公共子序列一定是最开始找到的 19 你找到的不是回文的子序列长度一定不大于是回文的 20 所以说你只要长度 21 直接输出没问题 22 你要序列 23 只找第一个就行 24 只要保证一个在前面一个在后面 25 两个匹配的 26 后面的不超过前面的 27 所以有了k 28 /*hud4512*/ 29 #include<stdio.h> 30 #include<string.h> 31 #include<algorithm> 32 #include<iostream> 33 using namespace std; 34 const int maxn = 210; 35 int a[maxn], b[maxn]; 36 int dp[maxn]; 37 int max(int a,int b) 38 { 39 if(a>b) return a; 40 return b; 41 } 42 int solve(int n,int m) 43 { 44 memset(dp,0,sizeof(dp)); 45 int ans = 1; 46 for(int i =1; i<=n; i++) 47 { 48 int tmp = 0; 49 for(int j =1; j<=(n-i+1); j++)//保证两个序列没有交集,不能遍历到m1 3 2 1 3就是反例 50 { 51 if(a[i] > b[j]) 52 tmp = max(tmp,dp[j]); 53 else if(a[i] == b[j]) 54 dp[j] = max(dp[j],tmp+1); 55 if(j<(n-i+1)) ans = max(ans, dp[j]*2); 56 else ans = max(ans, dp[j]*2-1);//那么说明j是中点 57 } 58 } 59 return ans; 60 } 61 62 int main() 63 { 64 int T; 65 int n; 66 scanf("%d",&T); 67 while(T--) 68 { 69 scanf("%d", &n); 70 for(int i = 1,j=n; i <= n; i++,j--) 71 { 72 scanf("%d", &a[i]); 73 b[j] = a[i]; 74 } 75 printf("%d ",solve(n,n)); 76 } 77 return 0; 78 }