[2019杭电多校第六场][hdu6635]Nonsense Time

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6635

题意是说一开始所有数都冻结,第i秒会解冻第ki个数,求每秒状态下的最长上上升子序列长度。

这种题一想添加操作就不好实现,所以干脆反着来,想删除操作。

从第n秒开始往前遍历,每次都会冻结一个数,这时判断一下这个数是否一定要在最长上升子序列里。

使用二分的方法求最长上升子序列,并且每次求完子序列后可以处理出那些位置是必须在最长上升子序列里的。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn = 5e4 + 10;
 9 int a[maxn], vis[maxn], ans[maxn], d[maxn], in[maxn], dp[maxn];
10 int len;
11 void  slove(int n) {
12     len = 0;
13     for (int i = 1; i <= n; i++) {
14         if (a[i] != 0) {
15             int pos = lower_bound(d + 1, d + 1 + len, a[i]) - d;
16             if (pos > len)
17                 d[++len] = a[i];
18             else
19                 d[pos] = a[i];
20             dp[i] = pos;
21         }
22     }
23     int q = len, limit = n;
24     for (int i = n; i >= 1; i--) {
25         if (dp[i] == q && a[i] <= limit && a[i] != 0) {
26             limit = a[i];
27             in[i] = 1;
28             q--;
29         }
30         else
31             in[i] = 0;
32     }
33 }
34 int main() {
35     int t;
36     scanf("%d", &t);
37     while (t--) {
38         int n;
39         scanf("%d", &n);
40         for (int i = 1; i <= n; i++)
41             scanf("%d", &a[i]);
42         for (int i = 1; i <= n; i++)
43             scanf("%d", &vis[i]);
44         slove(n);
45         for (int i = n; i >= 1; i--) {
46             ans[i] = len;
47             a[vis[i]] = 0;
48             if (in[vis[i]])slove(n);
49         }
50         for (int i = 1; i <= n; i++)
51             printf("%d%c", ans[i], i == n ? '\n' : ' ');
52     }
53 }

 

posted @ 2019-08-19 20:35  祈梦生  阅读(245)  评论(0编辑  收藏  举报