一、问题简析
本题考点是 最长上升子序列。
二分查找
根据模板,我们需要实现一个二分查找,找到 dp
中首个大于等于 A[i]
的元素。比较的规则是字典序。
// 按字典序比较A[a]和A[b],return A[a] < A[b]
bool cmp(const int &a, const int &b)
{
int mmin = min(cnt[a], cnt[b]);
for (int i = 0; i < mmin; ++i)
if (A[a][i] > A[b][i]) return false;
else if (A[a][i] < A[b][i]) return true;
if (cnt[a] < cnt[b]) return true;
else return false;
}
// 二分查找dp[i]中首个不小于A[key]的位置
int search(int key)
{
int L = 1, R = ptr;
while (L <= R)
{
int M = (R - L) / 2 + L;
if (cmp(dp[M], key))
L = M + 1;
else
R = M - 1;
}
return L;
}
哨兵元素
在模板中,需要将 dp
都初始化为 INF
。此出,按字典序,INF
为 Zzzzzzzzzzzz
。原因有两点:1、名字都是由一个大写字母加若干个小写字母构成;2、名字最长为10位。
记录子序列
模板中,dp
仅记录尾元素。在讨论元素 A[i]
时,二分找到了它在 dp
中的位置 j
,一定可以确定 dp[j - 1]
是它的前一个元素的下标。因此,我们只要记录每一个元素的前一个元素。最后,从最长上升子序列的尾元素开始,倒着找到所有元素。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 5;
int dp[MAX], pre[MAX], cnt[MAX], ptr; // ptr -- 元素个数
// dp[i] -- 长度i的序列的尾元素下标; pre[i] -- 下标i的元素的前一个元素的下标; cnt[i] -- 下标i的元素的长度
char A[MAX][15], s; // A[i] -- 下标i的元素; s -- 输入
// 按字典序比较A[a]和A[b],return A[a] < A[b]
bool cmp(const int &a, const int &b)
{
int mmin = min(cnt[a], cnt[b]);
for (int i = 0; i < mmin; ++i)
if (A[a][i] > A[b][i]) return false;
else if (A[a][i] < A[b][i]) return true;
if (cnt[a] < cnt[b]) return true;
else return false;
}
// 二分查找dp[i]中首个不小于A[key]的位置
int search(int key)
{
int L = 1, R = ptr;
while (L <= R)
{
int M = (R - L) / 2 + L;
if (cmp(dp[M], key))
L = M + 1;
else
R = M - 1;
}
return L;
}
int main()
{
#ifdef LOCAL
freopen("test.in", "r", stdin);
#endif
char ch;
while (true)
{
ch = getchar();
if (ch == EOF) break;
if (ch >= 'A' && ch <= 'Z') ++ptr; // 将输入元素分开
A[ptr][cnt[ptr]++] = ch;
}
sprintf(A[0], "Zzzzzzzzzzzz"); // 相当于INF
cnt[0] = 12;
for (int i = 1; i <= ptr; ++i)
{
int ans = search(i);
dp[ans] = i;
pre[i] = dp[ans - 1]; // 记录A[i]的前一个元素下标
}
int p = search(0);
p = dp[p - 1]; // 首个小于INF的元素A[p],即最长子序列的尾元素
stack<int> ans;
while (p != 0) // 逆序找到子序列中的所有元素
{
ans.push(p);
p = pre[p];
}
while (!ans.empty())
{
printf("%s", A[ans.top()]);
ans.pop();
}
return 0;
}
完
标签:cnt,return,int,P8736,元素,蓝桥,--,2020,dp From: https://www.cnblogs.com/hoyd/p/18214210