题目
模型
LIS的解法,大体来说有两种:
线性DP
1.状态定义:d(i),以位置i的元素结尾的LIS长度。
2.初状态:d[1…n] = 1。
3.答案:d[n]。
4.状态转移方程:
5.复杂度:
单调栈
使用数组B[1…],B[i]表示长度为i的LIS的最小尾元素值。
此处用到了贪心,即对于同一个长度的LIS,尾元素越小,越容易后面再加元素。
遍历A[1…n]维护B[1…],维护方法为:
- 当前元素A[i]>B[尾]时,插入;
- 当前元素A[i]<=B[尾]时,寻找第一个大于等于A[i]的B[j],令B[j] = A[i]。
此处的寻找用二分查找,因为
复杂度:
(遍历为n,二分查找为logn)
思路
本题稍微理解一下就知道,第一小问是求最长下降子序列,第二小问是求最长上升子序列,模型裸题。
洛谷用n2算法100分,nlogn算法200分。
代码
线性DP
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 200000 + 100;
int n, A[maxn], d[maxn];
int main() {
n = 0;
while (scanf("%d", &A[n]) == 1) n++;
_for(i, 0, n) d[i] = 1;
_for(i, 0, n)
for (int j = i - 1; j >= 0; j--)
if (A[i] <= A[j])
d[i] = max(d[i], d[j] + 1);
int ans = 1;
_for(i, 0, n) ans = max(ans, d[i]);
printf("%d\n", ans);
_for(i, 0, n) d[i] = 1;
_for(i, 0, n)
for (int j = i - 1; j >= 0; j--)
if (A[i] > A[j])
d[i] = max(d[i], d[j] + 1);
ans = 1;
_for(i, 0, n) ans = max(ans, d[i]);
printf("%d\n", ans);
return 0;
}
单调栈
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <functional>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 100000 + 100;
int A[maxn], B[maxn], n, len;
int main() {
n = 1;
while (scanf("%d", &A[n]) == 1) n++;
n--;
len = 1;
B[1] = A[1];
_rep(i, 2, n) {
int *p = upper_bound(B + 1, B + len, A[i], greater<int>());
if (*p >= A[i]) {
len++;
B[len] = A[i];
}
else *p = A[i];
}
printf("%d\n", len);
len = 1;
memset(B, 0, sizeof(B));
B[1] = A[1];
_rep(i, 2, n) {
int *p = lower_bound(B + 1, B + len, A[i]);
//if (*p != A[i]) p++; // p是第一个大于等于A[i]的元素所在位置
if (*p < A[i]) {
len++;
B[len] = A[i];
} else *p = A[i];
}
printf("%d\n", len);
return 0;
}
码农小技巧
lower_bound()和upper_bound在本题再次引起注意,因为这两个分不清瞎用导致本题卡了2h。。
upper_bound:返回的是键值为i的元素插入而不破坏容器顺序的最后一个位置。
lower_bound:返回的是键值为i的元素插入而不破坏容器顺序的第一个位置。
举例子:
- set里没有元素i的时候,两个元素的返回值是一样的。 1 2 4 5 这个序列,upp(3)和low(3)都返回位置2(下标)。
- 如果只有一个元素i,low返回那个元素的位置,而upp返回那个元素的位置的后一个位置。 1 2 4 5这个序列upp(2)返回下标2而low(2)返回下标1。
- 多个元素i,low返回那个元素的位置,upp返回那多个元素中的最后一个的后一个位置。 1 2 2 4 5 这个序列upp(2)返回下标3的位置,low(2)返回下标1的位置。
注意这里的后一个位置即可。
废话
好久没写题了,考试考的心乱,间隔了一个周多。
接下来的暑假写题写爆。
坐标大连海事大学,在此上自习,希望效率能高些。