HDU-5772 贪心策略+LIS [2016多校]

给定大小为N的序列,当某个元素为0时,可将其替换成任意整数;问能够得到的最长递增子序列长度。

贪心策略基于这样一个性质:
最优子序列是包含了所有原来为0的元素的子序列。
证明可以用反证法,设一个最长子序列中不包含某个0元素,那么我们必然可以:

  1. 用这个0元素替换它前面或者后面的已选非0元素,子序列长度不变;
  2. 子序列增加这个0元素,子序列长度变长;

无论如何都不会比原来的差。

所以A[i], A[j] (i<j) 选为子序列中连续元素的条件是:他们的差值必须大于其之间的0元素个数。

即:A[j]-A[i]>SUM[j]-SUM[i] (SUM[i]表示i号元素之前有多少个0元素)
转化一下即是:A[j]-SUM[j]>A[i]-SUM[i]
由以上这个式子,我们可以直接将所有A[i]修改为A[i]-SUM[i]之后,直接计算非0元素的LIS长度并加上0元素个数即可,非常妙。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
#define N 1050
int d[N];
int main(){
    int t,kase=0;
    cin>>t;
    while(t--){
        int n,zeros=0;
        cin>>n;
        vector<int> a;
        for (int i=0;i<n;i++){
            int x;
            cin>>x;
            if (x) a.push_back(x-zeros);
            else zeros++;
        }

        int cnt = 0;
        for (int i=0;i<a.size();i++){
            if (!cnt || a[i]>d[cnt-1]) d[cnt++] = a[i];
            int pos = lower_bound(d, d+cnt, a[i]) - d;
            d[pos] = a[i];
        }
        printf("Case #%d: %d\n", ++kase, cnt+zeros);
    }

    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,768评论 0 33
  • 动态规划(Dynamic Programming) 本文包括: 动态规划定义 状态转移方程 动态规划算法步骤 最长...
    廖少少阅读 3,322评论 0 18
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,215评论 0 52
  • 回溯算法 回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并...
    fredal阅读 13,725评论 0 89
  • 上午在中坞的练习很好,阳光灿烂。海亮老师做了详细讲解,了妈眼光独到,共修们同学们互相提醒、记录,真好! 晚上一家三...
    邵清清静阅读 158评论 1 3