참조 : https://oi-wiki.org/dp/basic/
O (n ^ 2) 알고리즘
매번 처음부터 스캔하여 최상의 답변을 찾으십시오.
int a[MAXN], d[MAXN];
int dp() {
d[1] = 1;
int ans = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j < i; j++)
if (a[j] <= a[i]) {
d[i] = max(d[i], d[j] + 1);
ans = max(ans, d[i]);
}
}
return ans;
}
O (nlogn) 알고리즘 이분법
이 기사 https://www.cnblogs.com/itlqs/p/5743114.html
을 참조 하면 코드는 다음과 같습니다.
for (int i = 0; i < n; ++i) scanf("%d", a + i);
memset(dp, 0x1f, sizeof dp);
mx = dp[0];
for (int i = 0; i < n; ++i) {
*std::upper_bound(dp, dp + n, a[i]) = a[i];
}
ans = 0;
while (dp[ans] != mx) ++ans;
샘플 질문 : https://vijos.org/p/1303
기술
특정 국가에서는 적의 미사일 공격을 방어하기 위해 미사일 차단 시스템을 개발했습니다. 그러나이 미사일 요격 시스템에는 결함이 있습니다. 첫 번째 포탄이 어떤 높이에도 도달 할 수 있지만 이후의 각 포탄은 이전 포탄보다 높을 수 없습니다. 어느 날 레이더가 적의 미사일 공격을 포착했습니다. 시스템이 아직 실험 단계에 있기 때문에 시스템이 하나뿐이므로 모든 미사일을 요격하지 못할 수도 있습니다.
체재
입력 형식
입력 데이터는 한 줄뿐입니다.이 줄에는 반폭 쉼표로 구분 된 여러 데이터가 포함되어 있으며 미사일의 높이를 차례로 나타냅니다 (최대 20 개의 미사일이 있고 높이는 30,000 이하의 양의 정수입니다. ).
출력 형식
한 줄의 출력 데이터 만 있고이 줄에는 쉼표로 구분 된 두 개의 데이터가 있습니다. 첫 번째 데이터는이 시스템이 요격 할 수있는 최대 미사일 수를 나타내고 두 번째 데이터는 모든 미사일을 요격하기 위해 이러한 시스템을 얼마나 더 추가해야하는지 나타냅니다.
예 1
샘플 입력 1
389,207,155,300,299,170,158,65
샘플 출력 1
6,1
한도
각 테스트 포인트의 시간 제한은 1 초입니다.
문제 해결
암호
#include <algorithm>
#include <iostream>
#include <stack>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1e5 + 2;
int dp[maxn]; // dp[k]表示长度为k的不下降子序列末尾元素的最小值
// int minh[maxn]; //记录从第i项开始,剩下最大能消灭的导弹数量
vector<int> v;
int up_bound(int l, int r, int x) {
//找到第一个大于x的数的下标
while (l < r) {
int mid = (r + l) / 2;
if (x >= dp[mid])
l = mid + 1;
else
r = mid;
}
return l;
}
int down_bound(int l, int r, int x) {
//找到第一个小于等于x的数的下标
for (int i = l; i <= r; i++)
if (dp[i] <= x) return i;
return r;
}
int main() {
char ch;
int n;
while (true) {
scanf("%d", &n);
v.push_back(n);
ch = getchar();
if (ch == '\n') break;
}
v.push_back(0);
reverse(v.begin(), v.end());
int len = 1;
dp[1] = v[1];
for (int i = 2; i < v.size(); i++) {
//求出最长不降子序列
if (v[i] >= dp[len]) {
dp[++len] = v[i];
} else {
int up = up_bound(1, len, v[i]);
dp[up] = v[i];
}
}
cout << len << ",";
//第二问就出最大下降子序列
len = 1;
dp[1] = v[1];
for (int i = 2; i < v.size(); i++) {
if (v[i] < dp[len])
dp[++len] = v[i];
else {
int down = down_bound(1, len, v[i]);
dp[down] = v[i];
}
}
cout << len - 1 << endl;
return 0;
}
/*90 103 99 83 102 70 86 70 99 71*/