题解
经典的最长上升子序列问题
数值过大使用离散化处理 数值过多使用二分优化dp
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e4 + 10;
int a[MAXN], d[MAXN], p[MAXN]; //d[i]以i为结尾的上升子序列长度 p[i]长度为i的最小结尾
vector<int> dz;
int Dis(int v)
{
return lower_bound(dz.begin(), dz.end(), v) - dz.begin();
}
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int N;
cin >> N;
for (int i = 1; i <= N; i++)
scanf("%d", &a[i]), dz.push_back(a[i]);
dz.push_back(-INF);
sort(dz.begin(), dz.end());
dz.erase(unique(dz.begin(), dz.end()), dz.end()); //数值过大 离散化
memset(p, 0x3f, sizeof(p));
p[0] = -INF;
int ans = 0;
for (int i = 1; i <= N; i++)
{
int k = lower_bound(p, p + N, Dis(a[i])) - p; //第一个大于等于当前值的长度
d[i] = k;
p[k] = min(p[k], Dis(a[i])); //更新p数组
ans = max(ans, d[i]);
}
cout << ans << endl;
return 0;
}
附带最开始蒙比了写的树状数组解法
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e4 + 10;
int a[MAXN], c[MAXN];
vector<int> dz;
inline int Lowbit(int x) //x二进制最低一位的1的值
{
return x & -x;
}
void Add(int x, int v, int n) //修改位置 修改值 最大下标 使用Add初始化c数组 要求下标范围从1开始
{
while (x <= n)
c[x] = max(c[x], v), x += Lowbit(x); //x + Lowbit(x) 父节点
}
int Ask(int x) //查询1~x前缀和
{
int res = 0;
while (x)
res = max(res, c[x]), x -= Lowbit(x); //x -= Lowbit(x) 兄弟节点
return res;
}
int Dis(int v)
{
return lower_bound(dz.begin(), dz.end(), v) - dz.begin();
}
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int N;
cin >> N;
for (int i = 1; i <= N; i++)
scanf("%d", &a[i]), dz.push_back(a[i]);
dz.push_back(-INF);
sort(dz.begin(), dz.end());
dz.erase(unique(dz.begin(), dz.end()), dz.end());
int ans = 0;
for (int i = 1; i <= N; i++)
{
int k = Dis(a[i]); //离散化
int res = Ask(k - 1); //查找小于k的最长长度
Add(k, res + 1, dz.size()); //记录当前长度
ans = max(ans, res + 1);
}
cout << ans << endl;
return 0;
}