• 【算法进阶指南】双端队列 DP+思维


    题目链接

    题意

    Sherry现在碰到了一个棘手的问题,有N个整数需要排序。Sherry手头能用的工具就是若干个双端队列。
    她需要依次处理这N个数,对于每个数,Sherry能做以下两件事:

    1. 新建一个双端队列,并将当前数作为这个队列中的唯一的数;

    2. 将当前数放入已有的队列的头之前或者尾之后。

    对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列。

    思路

    反着考虑,我们先将所有的数字排好序,然后尽可能少的分成连续的几段,使得每段都可以出现在一个双端队列中。

    分析一下可以知道,一个双端队列中的数字从头到尾的下标一定是先递减再递增,或者直接递增,或者直接递减。

    注意多个数字相同时,可以对他们的下标任意排序。

    首先处理出每个数字出现的最小下标和最大下标,按照数字大小排序之后进行DP。

    (dp[i][0]) 表示以第 (i) 个数字是升序的方式出现在队列中需要的最小的队列数。

    (dp[i][1]) 表示以第 (i) 个数字是倒序的方式出现在队列中需要的最小的队列数。

    初始化(dp[1][1] = dp[1][0] = 1)

    具体转移看代码

    代码

    #include <algorithm>
    #include <map>
    #include <queue>
    #include <stack>
    #include <stdio.h>
    #include <string.h>
    #include <vector>
    #define pb push_back
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int N = 3e5 + 10;
    const int mod = 1e9 + 7;
    using namespace std;
    
    vector<int> vec;
    map<int, int> minn, maxn;
    int dp[N][2];
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            vec.pb(x);
            maxn[x] = i;
            if (!minn[x])
                minn[x] = i;
        }
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        memset(dp, inf, sizeof(dp));
        dp[0][0] = dp[0][1] = 1;
        for (int i = 1; i < vec.size(); i++) {    //遇到降序时dp值才增加
            dp[i][0] = min(dp[i][0], dp[i - 1][1]);//在上次递减,这次递增,dp值不变
            if (minn[vec[i]] > maxn[vec[i - 1]]) {
                dp[i][0] = min(dp[i][0], dp[i - 1][0]);//在上次递增的基础上递增
            } else {
                dp[i][0] = min(dp[i][0], dp[i - 1][0] + 1);//上次递增,这次先递减再递增,dp值+1
            }
            dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1);//在上次递增,这次递减,dp值+1
            if (maxn[vec[i]] < minn[vec[i - 1]]) {//在上次递减的基础上再递减,dp值不变
                dp[i][1] = min(dp[i - 1][1], dp[i][1]);
            } else {
                dp[i][1] = min(dp[i][1], dp[i - 1][1] + 1);//上次递减,这次先递增再递减,dp值+1
            }
        }
        printf("%d
    ", min(dp[vec.size() - 1][0], dp[vec.size() - 1][1]));
        return 0;
    }
    
  • 相关阅读:
    [置顶] Objective-C,/,ios,/iphone开发基础:分类(category,又称类别)
    23个移动app界面上的旋钮和刻度盘设计示例
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to user’
    山沟沟里的实业路(3)
    挨踢江湖之十九
    如何用Python从本地将一个文件备份到Google Drive
    SQL Server 索引和表体系结构(包含列索引)
    UVa 263
    C语言之基本算法40—字符串删除元音字母倒序输出
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(1)
  • 原文地址:https://www.cnblogs.com/valk3/p/13907221.html
Copyright © 2020-2023  润新知