资源限制
时间限制:1.0s 内存限制:256.0MB
要求输出方案的最长上升子序列问题,O(n^2)的复杂度只能过前7个点,故采用O(nlogn)的复杂度求解
本题解就最长上升子序列的O(nlogn)复杂度的解决方法不做详细讲解(涉及贪心和二分相关知识),重点讨论输出最优方案
代码中用数组pos记录dp数组第i个字符串在s中的位置,f数组记录s[i]的上一个状态的末尾字符串在s中的位置, 对代码思考可知后达到最长的上升序列必然小于之前达到最长的上升序列,所以我们只需要记录最新的达到最长的子序列在s中的位置(记作k),代码如下
#include <iostream>
#include <algorithm>
using namespace std;
string str;
string s[1000005], dp[1000005];
int f[1000005], pos[1000005], g[1000005];
int n = 0;
int main()
{
ios::sync_with_stdio(0);
cin >> str;
for(int i = 0; i < (int)str.length(); i++)
{
if(str[i] >= 'A' && str[i] <= 'Z')
n++;
s[n] += str[i];
}
int len = 0, k = 0;//最新的达到最长的子序列在s中的位置(记作k),len是最长长度
for(int i = 1; i <= n; i++)
{
int p = lower_bound(dp+1, dp+1+len, s[i])-dp-1;
if(p+1 >= len)
k = i, len = p+1;
dp[p+1] = s[i], pos[p+1] = i;//pos记录dp数组第i个字符串在s中的位置
f[i] = pos[p];//记录s[i]的上一个状态的末尾字符串在s中的位置
}
for(int i = k; i; i = f[i])
{
g[f[i]] = i;//建立反向的链表关系,准备输出结果
}
for(int i = 0; i != k; i = g[i])
{
cout << s[i];
}
cout << s[k];
return 0;
}