CF 1035D Shurikens

题目描述

https://codeforces.com/contest/1435/problem/D

维护一个小根堆,每次有两种操作

向堆中加入一个数和取出堆顶 $x$

要求还原加数的序列

Solution

对于已经在堆里的元素来说,如果此时取出堆顶元素 $x$,说明堆内的元素都大于 $x$

换句话来说,越晚加入的元素的限制越弱

如果按照加入的顺序的话,我们大概能得到下面这种限制

且 $x_i$ 一定单调递减,假设我们现在要取出 $x$,那么贪心的进行选择一定要取出从左到右第一个小于 $x$ 的具有限制 $x_i$ 的那一段中的某一个

但是这样就相当于将这段以及后面段的限制都变成大于 $x$,那么就相当于取出最后面那段,我们发现这个东西符合先进后出,其实就是一个栈

所以我们模拟一下就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#define maxn 100010
#define ll long long
#define pb push_back
#define cn const node
#define cQ const Queue
#define gc getchar
#define INF 1000000000
using namespace std;

int read() {
int x = 0; char c = gc();
while (!isdigit(c)) c = gc();
while (isdigit(c)) x = x * 10 + c - '0', c = gc();
return x;
}

int n, a[maxn * 2];

char s[10];

struct node {
int k, v;

node() {}
node(int _k, int _v) { k = _k; v = _v; }
}; stack<node> S; int c1;

int ans[maxn];
int main() {
cin >> n;
for (int i = 1; i <= 2 * n; ++i) {
scanf("%s", s + 1);
if (s[1] == '+') a[i] = 0;
else scanf("%d", &a[i]);
}
for (int i = 1; i <= 2 * n; ++i)
if (!a[i]) S.push(node(++c1, 0));
else {
if (S.empty() || S.top().v > a[i]) return puts("NO"), 0;
ans[S.top().k] = a[i]; S.pop();
if (!S.empty() && S.top().v < a[i]) S.top().v = a[i];
}
puts("YES");
for (int i = 1; i <= n; ++i) printf("%d ", ans[i]);
return 0;
}

但是总感觉这样分析一道 $div2$ 的 $C$ 题有点过分了

所以我们换一个做法,我们这次考虑反着做

我们将取出堆顶 $x$ 视为加入数 $x$

加入一个数,我们视为取出一个数

我们发现连续一串加入的数 $x$ 一定是递减的

我们贪心的思考发现为了尽可能序列合法,我们一定在取出数时取出最小的数

因为这样可以尽可能的让下次加入的数做到递减(因为下次加入的数是固定的

因为加入的数是递减的,每次取出的时候又一定取最小的,所以这还是一个先进后出,所以还是一个栈(我tm

所以我们模拟一下即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#define maxn 100010
#define ll long long
#define pb push_back
#define cn const node
#define cQ const Queue
#define gc getchar
#define INF 1000000000
using namespace std;

int read() {
int x = 0; char c = gc();
while (!isdigit(c)) c = gc();
while (isdigit(c)) x = x * 10 + c - '0', c = gc();
return x;
}

int n, a[maxn * 2];

char s[10];

stack<int> S;

int ans[maxn], c1;
int main() {
cin >> n;
for (int i = 1; i <= 2 * n; ++i) {
scanf("%s", s + 1);
if (s[1] == '+') a[i] = 0;
else scanf("%d", &a[i]);
}
for (int i = 2 * n; i; --i)
if (!a[i]) {
if (S.empty()) return puts("NO"), 0;
ans[++c1] = S.top(); S.pop();
}
else {
if (!S.empty() && a[i] > S.top()) return puts("NO"), 0;
S.push(a[i]);
}
puts("YES");
for (int i = n; i; --i) printf("%d ", ans[i]);
return 0;
}