2020牛客寒假算法基础集训营6 C 汉诺塔 (dp 最长下降子序列)

https://ac.nowcoder.com/acm/contest/3007/C

将木板按照Xi从小到大排序,将这时的Yi数列记为Zi数列,则问题变成将Zi划分为尽可能少的若干组上升子序列。
根据Dilworth定理,最小组数等于Zi的最长下降子序列长度。
要求最长下降子序列的长度,我们有一种经典的二分优化dp的方法,在这里不再详述。 借助这种做法我们能给出一种构造方法,在求出最小组数的同时得出方案。
将状态数组的每个位置变为栈,用入栈操作代替修改元素操作,即可在求出组数的同时,用这些栈来完成对数列的划分。
 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5+5;
 4 struct node{
 5     int x,y;
 6     int indx;
 7     bool operator < (const node & b) const{
 8         return x < b.x;
 9     }
10 }g[maxn];
11 int dp[maxn],group[maxn];
12 int main(){
13     int n;cin>>n;
14     for(int i = 1;i<=n;i++) {
15         cin>>g[i].x>>g[i].y; 
16         g[i].indx = i;
17     }
18     sort(g+1,g+1+n);
19     int siz = 0;
20     for(int i = 1;i<=n;i++){
21         int l = 1,r = siz;
22         while(l<=r){//用二分进行优化时间复杂度
23             int mid = (l+r)/2;
24             if(dp[mid]<g[i].y) r = mid - 1;
25             else l = mid + 1;
26         }
27         dp[l] = g[i].y;
28         if(l > siz) siz = l;  
29         group[g[i].indx] = l; 
30     }
31     cout<<siz<<endl;
32     for(int i = 1;i<=n;i++){
33         cout<<group[i]<<" ";
34     }
35     return 0;
36 }

 

posted @ 2020-02-17 20:05  AaronChang  阅读(161)  评论(0)    收藏  举报