zoukankan      html  css  js  c++  java
  • P6198 、Can You Help ZSGW(洛谷月赛和武大校赛初赛题)

    牛客题目链接
    洛谷题目链接

    写分治类型的题太少了,而且看到一篇感觉很绝妙的写法,故学习之后,自己总结记录一下这个题

    题意:

    有一个排列,已知我们对于这个排列执行单调栈算法过程中,遍历到每一 个位置之后单调栈的大小,有些位置可能缺失,输入为-1。求一个满足这种情况 的字典序最小的排列。

    思路:

    首先我们应该做的事,是补全这个单调栈数组 b。单调栈数组由于单调栈 算法的特点,必然满足这么几个特点:

    • b[1] = 1
    • 若 b[i] > b[i −1],则 b[i] = b[i −1] +1,且 a[i] > a[i −1]。
    • 对于 b[i] <= b[i −1],一定有 a[i] < a[i −1]。

    我们从左到右依次补全每一个为 −1 的格子,那么策略应该是:

    • 若 i = 1,b[i] = 1。
    • 否则,如果我们填一个比 b[i −1] 小的数的话,在输出答案中, a[i −1] >a[i] ,在字典序上不会是个好主意。所以应该填 b[i −1] +1。
      补全数组之后,规律如下: 首先我们可以发现所有为 1 的位置组成了以最后一个 1 截止的降序序列。然后对 于每个被 1 分割的子区间,2 也会满足类似的规律。然后对于 2 进一步分 割的子区间 3 也会如此。

    代码:

    分治函数中,开始找出全部1的位置,按照降序依次填入数字,然后把vector为1的位置都删掉,然后对于每个分割的区间,使用2,3...。

    #include <iostream>
    #include<stdio.h>
    #include<vector>
    #include<string>
    #include<stack>
    #include<algorithm>
    using namespace std;
    #define auto vector<int>::reverse_iterator
    const int N=1e5+10;
    vector<int>v[N];
    stack<int>s;
    int n;
    int cur=1;
    int a[N];
    int b[N];
    //每次运行完,都能被保证v和s清空了
    
    void fill_arr(){
        a[1]=1;
        for(int i=2;i<=n;i++){
            if(a[i]==-1)a[i]=a[i-1]+1;
        }
    }
    void dfs(int l,int r,int pos){
        if(l>r)return;
        auto ed =v[pos].rend();
        for(auto i=v[pos].rbegin();i!=ed;i++){
            if(*i<=r)s.push(*i);
            else break;
        }
        while(!s.empty()&&s.top()>=l)b[s.top()]=cur++,s.pop();
        int xx = v[pos].back();
        dfs(l,xx-1,pos+1);
        v[pos].pop_back();
        while(!v[pos].empty()&&v[pos].back()<=r){
            dfs(xx+1,v[pos].back()-1,pos+1);
            xx = v[pos].back();
            v[pos].pop_back();
        }
        dfs(xx+1,r,pos+1);
        
    }
    void gao(){
        cur=1;
        fill_arr();
        for(int i=n;i;i--){
            v[a[i]].push_back(i);
        }
        dfs(1,n,1);
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            gao();
            for(int i=1;i<=n;i++)printf("%d ",b[i]);
            puts("");
        }
    }
    
  • 相关阅读:
    document.readyState的使用
    Selenium操作滚动条
    seq2seq模型以及其tensorflow的简化代码实现
    MOXA的Nport5600初始密码
    预测功率和电流之间的关系
    KNN与SVM对比&SVM与逻辑回归的对比
    拉格朗日乘子法以及KKT条件
    复合熵、条件熵和信息增益
    softmax为什么使用指数函数?(最大熵模型的理解)
    极大似然、最小二乘和梯度下降
  • 原文地址:https://www.cnblogs.com/gzr2018/p/12702999.html
Copyright © 2011-2022 走看看