吉哥系列故事——完美队形I

 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\n",solve(n,n));
76     }
77     return 0;
78 }

 

posted on 2013-08-05 16:03  ok_boy  阅读(245)  评论(0编辑  收藏  举报

导航