洛谷P1233 木棍加工【单调栈】

题目https://www.luogu.org/problemnew/show/P1233

题意:

有n根木棍,每根木棍有长度和宽度。

现在要求按某种顺序加工木棍,如果前一根木棍的长度和宽度都大于现在这根,那加工这一根就不需要准备时间,否则需要1分钟准备时间。

问最少的准备时间。

思路:

现在题目要同时维护两个单调不升序列的数目。对于一个属性显然可以通过排序保证他们是单调不升的。

只需在排好序之后求另一个属性的单调不升序列的个数。

这里需要知道Dilworth定理: 偏序集能划分成的最少的全序集的个数与最大反链的元素个数相等。

也就是说最长不升子序列的数目等于最长上升子序列的长度,最长上升子序列的数目等于最长不升子序列的长度。

问题转化成,对一个属性不升排序,再找另一个属性的最长上升子序列的长度。

扫描二维码关注公众号,回复: 6238792 查看本文章

用单调栈可以实现NlogN的求最长上升子序列长度,具体分析见导弹拦截

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x7fffffff
14 using namespace std;
15 typedef long long LL;
16 typedef pair<string, string> pr;
17 
18 int n;
19 const int maxn = 5005;
20 struct node{
21     int l, w;
22 }stick[maxn];
23 int sss[maxn], cnt = 0;
24 
25 bool cmp(node a, node b)
26 {
27     return a.l > b.l;
28 }
29 
30 int main()
31 {
32     scanf("%d", &n);
33     for(int i = 1; i <= n; i++){
34         scanf("%d%d", &stick[i].l, &stick[i].w);
35     }
36     
37     sort(stick + 1, stick + 1 + n, cmp);
38     
39     for(int i = 1; i <= n; i++){
40         if(stick[i].w > sss[cnt - 1]){
41             sss[cnt++] = stick[i].w;
42             //printf("%d\n", sss[cnt - 1]);
43         }
44         else{
45             int pos = lower_bound(sss, sss + cnt, stick[i].w) - sss;
46             sss[pos] = stick[i].w;
47         }
48     }
49     printf("%d\n", cnt);
50     
51     return 0; 
52 }

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/10863859.html