• 单调栈[Luogu P6198]


    新博客
    【题目描述】
    有一个长度为 (n) 的排列 (p_0, p_1, cdots, p_{n-1}),通过这个排列生成了一个长度为 (n) 的序列 (S),其中 (S_i) 表示由 (p_0, p_1, cdots, p_i) 组成的递增单调栈的大小。

    换一种说法,序列 (S) 是由如下代码生成的:

    stack<int> stk;
    int n = p.size();
    vector<int> S;
    for (int i = 0; i < n; i++) {
        while (!stk.empty() && p[i] <= p[stk.top()]) stk.pop();
        stk.push(i);
        S.push_back((int)stk.size());
    }
    

    现在给你序列 (S) 的一部分,没有给出的部分可以取任意值。请你根据给出的 (S) 复原出排列 (p)。如果有多种可能,输出字典序最小的。保证一定有解。

    【输入格式】
    第一行一个整数 (n)。表示排列的长度。

    接下来一行 (n) 个整数,表示序列 (S)。其中部分项为 (-1),表示可以取任意值。

    【输出格式】
    一行 (n) 个整数,一个排列。

    没有打洛谷月赛。。。但是此题似乎很可做 于是就花了半个多小时切掉了

    题解

    这题整体是一个贪心+递推的思路

    假设我们已经确定了 由(S_1sim S_{i-1})推出的 字典序最小的 由(1sim i-1)构成的排列(p),以及(p)当前的递增单调栈(stk) 注意这里的栈里存的是元素的值而不是下标

    那么考虑一下怎么在(p)中插入(i)这个元素使得字典序最小

    但是插入(i)这个操作我们并不好处理

    不妨这样考虑 将原来(p)中所有(ge x)的元素全部+1 然后在(p)的末尾加上一个(x) 容易证明这样得到的(p)序列对应的(S_1sim S_{i-1})仍与原来一样

    那么(x)要满足什么条件才能使得(S_i)恰好为要求的值呢 考虑一下(i-1)的递增单调栈(stk) 必须要有(stk[S_i-1]<xle stk[S_i]) 这样(stk[S_i]sim stk[top])都会被弹出

    为了使字典序最小 显然我们这里就让(x=stk[S_i]) 于是我们就得到了转移

    所以算法流程如下:

    已知:字典序最小的 由(1sim i-1)构成的 满足(S_1sim S_{i-1})要求的排列(p) 以及(p)当前的递增单调栈(stk) 大小为(top)

    (x=stk[S_i]) 将当前(p)中所有(ge x)的元素+1 然后将(x)放到(p)的末尾 更新单调栈

    (S_i=-1)或者(S_i>top)的时候直接把(i)扔到(p)的末尾就可以了

    但是大家应该都发现了 这个是(O(n^2))

    无非就是 将所有(ge x)的元素+1 这一步耗费了太多时间 怎么(O(1))(O(log n))解决呢?

    不用什么数据结构 这里有一个奇技♂淫巧

    1.如果我们要把(i)放到(p)的末尾 我们不放(i) 我们放一个(i*1000005)(或者乘上任意一个大于(n)的数)

    2.如果我们要令(x=stk[S_i]) 然后将当前(p)中所有(ge x)的元素+1 我们不用去一个个+1 只需要让(x=stk[S_i]-1)然后放到末尾就完事了

    最后把这么做得到的答案排个序离散化一下就得到正确答案了 就算极限情况下 符合条件的(p)是一个(nsim 1)的倒序排列 由于我们乘的数大于(n) 也不会出错

    时间复杂度(O(nlog n)) 不知道有没有(O(n))做法 但是由于代码中带(log)的只有一个sort 所以跑过(1e6)还是毫无压力的

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll; 
    
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ '0');
    	return x * f;
    }
    
    int n, a[1000005], top;
    ll stk[1000005], ans[1000005], srt[1000005], mx;
    
    int main() {
    	n = read(); 
    	for (int i = 1; i <= n; i++) {
    		a[i] = read();
    	}
    	for (ll i = 1; i <= n; i++) {
    		if (a[i] == -1) {
    			ans[i] = i * 1000005;
    			stk[++top] = ans[i];
    		} else {
    			if (a[i] > top) {
    				ans[i] = i * 1000005;
    				stk[++top] = ans[i];
    			} else {
    				ans[i] = stk[a[i]] - 1;
    				stk[top = a[i]] = ans[i];
    			}
    		}
    	}
    	for (int i = 1; i <= n; i++) srt[i] = ans[i];
    	sort(srt + 1, srt + n + 1);
    	for (int i = 1; i <= n; i++) ans[i] = lower_bound(srt + 1, srt + n + 1, ans[i]) - srt;
    	for (int i = 1; i <= n; i++) printf("%lld ", ans[i]);
    	return 0;
    } 
    
  • 相关阅读:
    [CodeForces]Codeforces Round #429 (Div. 2) ABC(待补)
    About Me
    2018-06-14
    Codeforces Codeforces Round #484 (Div. 2) E. Billiard
    Codeforces Codeforces Round #484 (Div. 2) D. Shark
    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings
    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes
    Codeforces Avito Code Challenge 2018 D. Bookshelves
    Codeforces Round #485 (Div. 2) D. Fair
    Codeforces Round #485 (Div. 2) F. AND Graph
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM49.html
Copyright © 2020-2023  润新知