程式設計師的揹包 ZZULIOJ - 2485 離散化 dp lis | 樹狀陣列
阿新 • • 發佈:2019-01-13
題解
經典的最長上升子序列問題
數值過大使用離散化處理 數值過多使用二分優化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;
}