题目链接
解题思路
简化之后,这道题就是要求上升序列的最少数目,也就是最少上升子序列的划分数目,也就是求下降子序列的最大长度。
这题用dp来做的话会很险,dp的时间复杂度是
O
(
n
2
)
O(n^2)
O(n2),这题
n
n
n 达到了
e
4
e^4
e4,时间级就是
e
8
e^8
e8 很容易TLE。所以用另外一种方法做,时间复杂度是
n
l
o
g
(
n
)
nlog(n)
nlog(n)。
源代码如下:
#include <iostream>
#include <algorithm>
#define NUM 10050
#define MIN -1
using namespace std;
int dp[NUM];
int a[NUM];
bool cmp(int a, int b) {
return a > b;
}
void solve(int n) {
fill(dp, dp + n, MIN);
for (int i = 0; i < n; ++i) {
int index = lower_bound(dp, dp + n, a[i], cmp) - dp;
dp[index] = a[i];
}
}
int main(int argc, char** argv) {
int n;
while (cin >> n) {
for (int i = 0; i < n; ++i) {
scanf("%d", a+i);
}
solve(n);
int i;
for (i = 0; i < n; ++i) {
if (dp[i] == MIN) break;
}
printf("%d\n", i);
}
return 0;
}
这题问题的转换是依据dilworth 定理,具体实现:上升链的最少划分数=下降链的最大长度。
另外关于求最长上升子序列,推荐《挑战程序设计竞赛》这本书。最长下降子序列和最长上升子序列的方法几乎一样,理解了最长上升子序列,最长下降子序列也就OK了。