游园安排【蓝桥杯第十一届】【决赛】【A组】(最长上升子序列(贪心,二分搜索)+输出)
思路:
- 就是求最大的上升子序列(字母字典序版本,直接比较就行了,系统自动排)
- 思路: 维护一个严格上升的子序列,让里面的元素尽量小,
- 既 一个新来的东西, 大于最大值,就排在末尾,然后就在子序列里找到第一个大于等于的这个数(为什么要大于等于,因为是要严格上升),然后把他替换掉
- 找的时候用 lower_bound 就行了, 是一种贪心的思想,我不好解释 qwq
- 输出的时候也是一种贪心的思想, 逆序找,看他这个字符 的 size 是不是 当前的size,是 就代表他是最小的,且符合题意的,应为在后面的字符还能更新那么他一定是比前面小于或者等于的,就看他的size是不是符合!!

#include <bits/stdc++.h> using namespace std; #define ri register int #define M 1000005 int n,m; string p[M]; string q[M]; int num[M]; string ans[M]; int main(){ ios::sync_with_stdio(false); cin.tie(0); string s; cin>>s; string tmp; for(ri i=0;i<s.length();i++) { if(s[i]>='A'&&s[i]<='Z'&&i!=0) { p[++n]=tmp;tmp=s[i];continue; } tmp+=s[i]; } p[++n]=tmp; int r=1; q[r]=p[1]; num[r]=1; for(ri i=2;i<=n;i++) { if(p[i]>q[r]) { q[++r]=p[i]; num[i]=r; } else { int a=lower_bound(q+1,q+1+r,p[i])-q; q[a]=p[i]; num[i]=a; } } for(ri i=n,j=r;i>=1;i--) { if(num[i]==j) { ans[j]=p[i]; j--; } } for(ri i=1;i<=r;i++) { cout<<ans[i]; } return 0; }