OCAC暑期比赛第二场 M题 队列的序列 题解

队列的序列
【题目描述】
现在告诉你有一个队列,一开始它是空的,首先你会把 1,2,3,…m 这 m 个数依次push入这个队列。
接着,会进行 n 次操作,每次操作你需要进行如下操作:
首先,获得队首元素,输出队首元素,并且将这个队首元素pop出队列;然后你可以在如下两个选择中任选一个操作:
1. 将这个队首元素永远的抛弃;
2. 将这个队首元素重新加入到队尾中。
现在告诉你 n 和 n 次操作所输出的队首元素,需要你判断是否存在一个数 m 使得这个操作是可行的。
【输入格式】
第一行一个正整数 n ,用于表示操作的次数。(1≤n≤100000)
第二行 n 个正整数,以空格分隔,用于表示 n 次操作所输出的队首元素。
【输出格式】
如果存在一个数 m 使得这 n 次操作可行,输出“YES”;否则,输出“NO”。
【样例 1 输入】
5
1 2 3 1 2
【样例 1 输出】
YES
【样例 2 输入】
5
1 2 3 2 1
【样例 2 输出】
NO
【样例解释】
对于样例 1,当 m==3 时,我们执行如下操作就可以得到目标序列 [1,2,3,2,1]
初始时,que = [1,2,3]
step.1: 输出 1 = que.front(), que.pop(), que.push(1), 此时 que = [2,3,1]
step.2: 输出 2 = que.front(), que.pop(), que.push(2),此时 que = [3,1,2]
step.3: 输出 3 = que.front(), que.pop(), que.push(3), 此时 que = [1,2,3]
step.4: 输出 1 = que.front(), que.pop(), 此时 que = [2,3]
step.5: 输出 2 = que.fornt(), que.pop(), 此时 que = [3]
那么我们输出的序列就是 [1,2,3,1,2],所以 m==3 是存在的。这个序列合法,我们输出“YES”。
对于样例 2,我们没有办法得到m。
因为我们在 1, 2, 3 之后输出了 2,也就是说我一开始抛弃了 1 ,并且 m==3,那么到此我输出 2 是合法的,
但是我在2 之后又输出了 1,但是模拟到这里我们可以明显看出 1 肯定是在之前被抛弃了。所以你个序列不合法,输出“NO”。
【问题分析】
这道题目是一道关于队列的模拟题。
模拟题呢,它就是模拟一类东西的实现。
如果是一道关于电梯的模拟题,我们就要先了解电梯的原理,那么我们做起模拟题就会得心应手。
那么对于队列的模拟题呢,我们也是要了解了队列的操作之后,再去找规律。
首先我们会发现m是很好找的,因为一个合法的序列的话,它的前m个数据肯定是1,2,3,...,m。
所以如果不满足这个性质,那么这个序列就不合法。
或者说,如果我们找到了m,但是之后序列里面存在一个元素比 m 大,那也是不合法的。
然后我们开始看序列的第 m+1 到 第 n 个元素,
他们可以分解成若干个连续上升子序列,并且如果这些子序列中的前一个不包含后一个,那么就是不合法的。
举个例子,如下一个序列:
1, 2, 3, 4, 5, 2, 3, 5, 3, 4
根据前5个元素,我们能够确定 m == 5
然后我们将第 5 个元素开始的序列分成若干个连续上升子序列,那么,分割后(包含前5个元素)的序列组如下:
    [1, 2, 3, 4, 5]
    [2, 3, 5]
    [3, 4]
根据第1个和第2个子序列,我们可以确定第1轮剔除掉了1和4;
然后我们再去看第3个子序列,其中存在4,但是第1轮已经去掉了4,所以这种存在不合法。输出“NO”。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, a[maxn], m;
bool cut[maxn];

void get_m() {
    m = -1;
    if (a[1] != 1) return;
    for (int i = 2; i <= n; i ++) {
        if (a[i] > a[i-1] + 1) return;
        if (a[i] <= a[i-1]) { m = a[i-1]; return; }
    }
    m = n;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    get_m();    // 得到 m
    if (m == -1) {
        puts("NO");
        return 0;
    }
    for (int i = m+1; i <= n; i ++) {   // 判断有没有数大于 m
        if (a[i] > m) {
            puts("NO");
            return 0;
        }
    }
    queue<int> que1, que2;
    for (int i = 1; i <= m; i ++) que1.push(i);
    for (int i = m+1; i <= n; i ++) {
        while (!que1.empty() && que1.front() != a[i]) que1.pop();
        if (!que1.empty() && que1.front() == a[i]) {
            que2.push(que1.front());
            que1.pop();
        }
        else {
            while (!que2.empty()) {
                que1.push(que2.front());
                que2.pop();
            }
            while (!que1.empty() && que1.front() != a[i]) que1.pop();
            if (!que1.empty() && que1.front() == a[i]) {
                que2.push(que1.front());
                que1.pop();
            }
            else {
                puts("NO");
                return 0;
            }
        }
    }
    puts("YES");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ocac/p/11131692.html
今日推荐