链接:游园安排【第十一届】
题意:
思路:
首先,读懂题意后发现就是求最长上升子序列,但是数据有1e6,并且要求字典序最小。那么我们可以用线段树维护当前最长上升子序列并且同时维护当前最小串。
- 我们从后往前遍历,对于当前位置,找到后面的长度最大并且名字最小的位置,这样维护出来的串就能保证字典序最小了。
- 还需要记录答案,我们只需用一个数组记录每一个名字后面跟的是哪一个名字即可。最后找到长度最大且开头最小的位置,循环一遍即可。
- 为什么要从后往前呢 ,例如 2 5 1 5 6 ,如果从前往后的话到6就不知道选前面哪个 5 了 , 但是从后往前你选的一定是1开头的最长上升子序列。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
const int maxn=1e6+5,inf=1e9;
const int mod = 1e9 + 7;
using namespace std;
char s[maxn];
int a[maxn] , dp[maxn] , suf[maxn];
map<string ,int>mp;
string st[maxn];
vector<string> vec , vec1;
struct node{
int name , le , pos;
}sum[maxn << 2];
node Max(node a , node b){
if(a.le > b.le) return a;
if(a.le < b.le) return b;
if(a.name < b.name) return a;
return b;
}
void update(int pos , node val, int l ,int r , int rt){
if(l == r){
sum[rt] = Max(val , sum[rt]);
return ;
}
int mid = (l + r) / 2;
if(pos <= mid) update(pos , val , l , mid , rt << 1);
if(pos > mid) update(pos , val , mid + 1 , r , rt << 1 | 1);
sum[rt] = Max(sum[rt << 1] , sum[rt << 1 | 1]);
}
node query(int L , int R,int l , int r,int rt){
node ans = {0, 0 , 0};
if(L <= l && R >= r){
return sum[rt];
}
int mid = (l + r) / 2;
if(L <= mid) ans = Max(ans , query(L , R , l , mid , rt << 1));
if(R > mid) ans = Max(ans , query(L , R , mid + 1 , r , rt << 1 | 1));
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin>>s + 1;
int len = strlen(s + 1);
for(int i = 1; i <= len; i ++){
if(s[i] >= 'A' && s[i] <= 'Z'){
string now = "";
now += s[i];
while(i + 1 <= len && s[i + 1] >= 'a' && s[i + 1] <= 'z'){
now += s[i + 1];
i ++;
}
vec.push_back(now);
vec1.push_back(now);
}
}
sort(vec1.begin() , vec1.end());
vec1.erase(unique(vec1.begin(), vec1.end()), vec1.end());
for(int i = 0; i < vec1.size(); i ++){
mp[vec1[i]] = i + 1;
st[i + 1] = vec1[i];
}
for(int i = 0; i < vec.size(); i ++){
a[i + 1] = mp[vec[i]];
}
int n = vec.size() , m = vec1.size() + 1;
for(int i = n; i >= 1; i --){
node now = query(a[i] + 1 , m , 1 , m , 1);
dp[i] = now.le + 1;
update(a[i] , {a[i] , dp[i] , i} , 1 , m , 1);
suf[i] = now.pos;
}
int pp = query(1 , m , 1 , m , 1).pos;
while(pp != 0){
cout<<st[a[pp]];
pp = suf[pp];
}
return 0;
}