HDU - 5773 贪心 + LIS

题意:

给出一串序列,其中每个0可以转化成任何数,问转化过后,最长的严格递增子序列的长度。

思路:

贪心的思路很巧妙,首先如果是排在LIS的左右两端的0,都可以不考虑,最后再加上,因为0可以变成任何数。
如果是出现在中间的0,可以这样思考,因为0可以变成任何数,灵活度最高,所以最后能求出的最长上升子序列一定至少有一种情况是包含了所有的0。
既然0肯定会出现在最终的结果LIS中,那么我们不考虑0,直接求其余部分的LIS,最后再加上0的个数不就行了。
但是要注意,既然不考虑0,也要消去0对其余部分的影响,如序列:x,0,0,y,如果不考虑0,也就是说想把两个0都算到最后的LIS结果中,若0之前的LIS末尾为x,这两个0分别算作x+1和x+2,再后面的数至少要是x+3才能再被算入LIS中,如果不考虑0,那么将这之后的所有数都减去之前出现过的0的个数,仍要满足LIS,这样最后的结果也就会出现这些数。
比如:1,2,0,0,4,5,消去0的影响之后是1,2,2,3,这样求出的LIS是3,其实也就是取了1,2,5,这样再加上两个0,最终答案就是5
剩下的就是二分求LIS即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 111111;

int a[MAXN], dp[MAXN];

int main() {
    int T, cs = 0;
    scanf("%d", &T);
    while (T--) {
        int n, m = 0, cnt = 0, x;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &x);
            if (!x) ++cnt;
            else a[++m] = x - cnt;
        }
        fill(dp + 1, dp + 1 + m, INF);
        for (int i = 1; i <= m; i++) {
            int pos = lower_bound(dp + 1, dp + 1 + m, a[i]) - dp;
            dp[pos] = a[i];
        }
        int ans = lower_bound(dp + 1, dp + 1 + m, INF) - dp - 1;
        ans += n - m;
        printf("Case #%d: %d\n", ++cs, ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值