• 【hdu】4521 小明序列【LIS变种】【间隔至少为d】


    题目链接:https://vjudge.net/contest/228455#problem/B

    转载于:https://blog.csdn.net/a709743744/article/details/51765252

    题目大意:

    求最长上升子序列,其中子序列中相邻的两个数的下标差要超过k

    解题分析:

    子序列中相邻的两个数的下标要超过k,要想满足这个条件我们可以按下面的思路想:

    首先nlogn的LIS是毫无疑问的,然后再这个算法中,我们每次二分找到当前数的位置,如果数组中的数比当前数大的话就更新数组

    所以我们可以稍微改一下上述步骤,当我们二分计算当前数的位置时,只是把当前数应该在数组中的位置保存下来,当前只更新在i - k之前的那个数,

    这样我们就可以保证每次二分查找时,数组中的所有数的下标都比当前的下标少至少k.

    然而我还是没有弄懂,先记录着吧。

    这是我的代码,用结构体,然后套用了一下LIS模板,不知道为什WA

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int MAXN = 1e5 + 100;
    int n, d;
    struct node
    {
        int val, ord;
    }arr[MAXN],lis[MAXN];
    
    int find(int l, int r, int key)
    {
        if (l == r)return l;
        int mid = (l + r) >> 1;
        if (key>lis[mid].val)return find(mid + 1, r, key);
        else return find(1, mid, key);
    }
    
    int main()
    {
        while (scanf("%d %d", &n, &d) != EOF){        //注意是下标之差大于d,而不是值之差大于d
            memset(arr, 0, sizeof(arr));
            for (int i = 1; i <= n; i++) {
                scanf("%d", &arr[i].val);
                arr[i].ord = i;
            }
            int len = 0;
            for (int i = 1; i <=n; i++){
                if (i == 1)lis[++len] = arr[i];
                else if (arr[i].val > lis[len].val) {
                    if ((arr[i].ord - lis[len].ord) > d)lis[++len] = arr[i];
                }
                else
                {
                    int j = find(1, len, arr[i].val);
                    if (j != len){
                        if (j == 1){
                            if ((lis[2].ord - arr[i].ord) > d)lis[j] = arr[i];
                        }
                        else{
                            if ((lis[j + 1].ord - arr[i].ord) > d && (arr[i].ord - lis[j - 1].ord) > d)
                                lis[j] = arr[i];
                        }
                    }
                }    
            }
            printf("%d
    ", len);
        }
        return 0;
    }
    View Code

    ACLIS解法

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include <algorithm>
    #define maxn 100005
    using namespace std;
    int a[maxn], b[maxn], p[maxn];
    int n, d;
    
    int find(int p)   //二分查找<=p的位置+1
    {
        int l, r, mid;
        l = 1, r = n, mid = (l + r) >> 1;
        while (l <= r){
            if (p>b[mid]) l = mid + 1;
            else if (p<b[mid]) r = mid - 1;
            else return mid;
            mid = (l + r) >> 1;
        }
        return l;
    }
    
    int LIS(){
        int i, j, ans = 0;
        for (i = 1; i <= n; i++){
            p[i] = find(a[i]);         //p[i]存的是a[i]在上升数组中的位置
            ans = max(ans, p[i]);
            j = i - d;
            if (j>0) b[p[j]] = min(b[p[j]], a[j]);
        }
        return ans;
    }
    
    int main()
    {
        int i, res;
        while (cin >> n >> d){
            for (i = 1; i <= n; i++){
                scanf("%d", &a[i]);
                b[i] = maxn;
            }
            res = LIS();
            printf("%d
    ", res);
        }
        return 0;
    }

    dp    AC解法

    #include<cstdio>  
    #include<cstring>  
    #include<iostream>  
    #include<algorithm>  
    #define INF 0x3f3f3f3f  
    using namespace std;
    const int maxn = 100000 + 10;
    int a[maxn], dp[maxn], g[maxn], n, k;
    
    int main()
    {
        while (~scanf("%d%d", &n, &k))
        {
            int ans = -1;
            memset(dp, 0, sizeof(dp));
            memset(g, INF, sizeof(g));
            for (int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            for (int i = 1; i <= n; i++)
            {                                                                   //延迟p位更新             //为什么我感觉i>k+1以后还是连续的,下标并没有相差k啊???搞不懂
                if (i - k - 1>0)  g[dp[i - k - 1]] = min(a[i - k - 1], g[dp[i - k - 1]]);        // i-p>1 是因为下标j范围为1<j<=m
                dp[i] = lower_bound(g + 1, g + 1 + n, a[i]) - g;       //先记录下a[i]在g数组中的位置       
                ans = max(ans, dp[i]);
            }
            cout << ans << endl;
        }
        return 0;
    }

    2018-05-17

  • 相关阅读:
    值类型引用类型的区别(转)
    聚集索引和非聚集索引(转)
    使用docker安装nginx并配置端口转发
    jenkins选择分支构建
    创建好docker后不能apt-get update解决方法
    Docker开启Remote API 访问 2375端口
    Docker加速配置
    Docker下载安装
    进入Docker 容器 docker exec [CONTAINER ID] bin/bash报错问题
    定时删除日志文件---linux定时清理日志
  • 原文地址:https://www.cnblogs.com/00isok/p/9050736.html
Copyright © 2020-2023  润新知