CDOJ 251 导弹拦截 最长递增子序列

点击打开链接

就是寻找LIS 并打印出来

dp[i]表示到包括第i个数的前i个的最长递增的长度

从数列从后往前找就好了 ,如果从前往后,前面的大数会覆盖掉后面的小数,就不对了


代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 1e5+10;
 5 
 6 int a[maxn],dp[maxn],ans[maxn];
 7 vector<int> v;
 8 
 9 int main(){
10     int t; cin>>t;
11     while(t--){
12         int n; cin >> n;
13         for(int i=1; i<=n; i++)
14             cin >> a[i];
15         memset(ans,0x3f,sizeof(ans));
16         memset(dp,0,sizeof(dp));
17         v.clear();
18         int mx = -1;
19         for(int i=1; i<=n; i++){
20             int p = lower_bound(ans+1,ans+1+n,a[i])-ans;
21             ans[p] = a[i];
22             dp[i] = p;
23             mx = max(mx,p);
24         }
25 
26         cout << mx << endl;
27         int k = maxn;
28         for(int i=n; i>=1; i--){
29             if(dp[i]==mx && a[i]<k){
30                 v.push_back(a[i]);
31                 k = a[i];
32                 mx--;
33             }
34         }
35         // int k = -1,cnt=1;
36         // for(int i=1; i<=n; i++){ // 不能正序,前面大的数会覆盖后面小的数 不能达到最长
37         //     if(dp[i]==cnt && a[i]>k){
38         //         v.push_back(a[i]);
39         //         k = a[i];
40         //         cnt++;
41         //     }
42         // }
43 
44         for(int i=v.size()-1; i>=1; i--)
45             cout << v[i] << " ";
46         cout << v[0] << endl;
47     }
48 }
原文地址:https://www.cnblogs.com/yxg123123/p/6827734.html