贴个线段树的解法
#include<cstdio>
#include<iostream>
#include<sstream>
#include<utility>
#include<cmath>
#include<cassert>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<tuple>
using namespace std;
struct Node
{
char min_val; // 当前区间字典序最小的字符
int min_pos; // 最小字符的索引(在原字符串中的位置)
int l;
int r;
Node * left;
Node * right;
};
auto top = 0;
Node pool[(100000 + 5) * 4];
// 建树
Node * build(const string & S, int l, int r)
{
auto root = &pool[top++];
root->l = l;
root->r = r;
if(l + 1 == r)
{
root->left = nullptr;
root->right = nullptr;
root->min_val = S[l];
root->min_pos = l;
}
else
{
auto mid = (l + r) / 2;
root->left = build(S, l, mid);
root->right = build(S, mid, r);
root->min_val = min<int>(root->left->min_val, root->right->min_val);
root->min_pos = root->left->min_val <= root->right->min_val ? root->left->min_pos : root->right->min_pos;
}
return root;
}
// 返回区间[l, r)上字典序最小的字母及其索引
tuple<char, int> find_tree(Node * root, int l, int r)
{
if(l <= root->l && root->r <= r)
{
return make_tuple(root->min_val, root->min_pos);
}
auto mid = (root->l + root->r) / 2;
auto left_res = make_tuple(numeric_limits<int>::max(), -1);
auto right_res = make_tuple(numeric_limits<int>::max(), -1);
if(l < mid) left_res = find_tree(root->left, l, r);
if(mid < r) right_res = find_tree(root->right, l, r);
if(get<0>(left_res) <= get<0>(right_res))
{
return left_res;
}
else return right_res;
}
int main()
{
int K;
cin >> K;
string S;
cin >> S;
auto root = build(S, 0, S.size());
string acc;
auto start = 0;
for(auto cur_K = K; cur_K > 0; --cur_K)
{
auto t = find_tree(root, start, S.size() - cur_K + 1);
acc += get<0>(t);
start = get<1>(t) + 1;
}
cout << acc << "\n";
return 0;
}
不好意思啊,这题我好像不怎么明白题目含义。。。lexicographically smallest string,指的是“字典序最小”? 那样例S=cacbbac 满足条件的不应该是abba吗?
abb aba的字典序谁大?
哦 我以为是总的字典序最小(*/ω\*)