拦截导弹

拦截导弹

题意: 最少用几个不上升子序列完全覆盖原序列.

贪心:

处理一个不下降队列, 队列中的每个数都表示我们需要求得的不上升子序列的末尾.那么最终队列有多少个数,就表示答案是多少.

为了处理出这个队列q,我们遍历原数组s,对于每一个x:

  • x大于等于q中每一个数,把x放到q的末尾
  • 否则,找到q中第一个大于等于x的数,将这个数替换为x

由于q每次增加长度时,q中的每个数相对大小关系不变,所以q就是原数组s的不下降子序列.

于是得出结论:

  • 能覆盖整个序列的最少的不上升子序列的个数等价于该序列的最长上升子序列长度
  • 能覆盖整个序列的最少的不下降子序列的个数等价于该序列的最长下降子序列长度
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define ull unsigned long long
int a[N], q[N];
#define pb push_back
#define PII pair<int, int>
#define VIT vector<int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 1010; 
int f[N];
int n;
 
int main() {
    //freopen("in.txt", "r", stdin);
    IO;
    int x;
    while (cin >> x) a[++n] = x;
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        f[i] = 1;
        for (int j = 1; j < i; ++j)
            if (a[i] <= a[j]) f[i] = max(f[i], f[j] + 1);
        ans = max(ans, f[i]);
    }
    cout << ans << '\n';
    int cnt = 0;
    for (int i = 1; i <= n; ++i) {
        int k = 0;
        while (k < cnt && a[q[k]] < a[i]) ++k;
        q[k] = i;
        if (k >= cnt) ++cnt;
    }
    cout << cnt << '\n';
    return 0;
}
posted @ 2021-04-10 10:55  phr2000  阅读(49)  评论(0编辑  收藏  举报