D. Shurikens 思维

D. Shurikens 思维

题目大意:

给一个N,代表有N个物体,编号1->N。
接下来是2*N行,遇到 + 代表将某一物品放到桌子上,遇到减号和数字,代表从桌子上把编号为这个数字的物品拿走了。
问在每一个加号后面能否加上一个数字 ,代表将序号为这个数字的物品放到桌子上,使得这个拿东西和放东西的操作序列符合(每次拿走物品都是拿走桌子上当前序号最小的物品,并且拿东西的时候有东西可拿)这个条件,如果可以输出YES,输出数字序列,如果不可以输出NO即可。

题解:

写这个题目的题解不是因为这个题目难,而是因为这个题目的一个解法我觉得很有意思,但是我又没想到。

我写的解法很复杂,单调栈 + 线段树。

  • 单调栈维护一下递减的序列,然后对于每一个 - x,找到大于 x 的第一个位置的后面一个位置 \(l\),然后贪心的考虑在区间 \([l,i]\) ( \(i\) 表示此时这个位置) ,找到最靠前面的一个位置分配给他。

然后上网搜了一下,发现一个很简洁的题解:

https://www.bilibili.com/read/cv8098598

如果不太理解可以看看:https://blog.csdn.net/qq_30361651/article/details/109292134

  • 如果是 YES,那么对于第 \(i\) 个人 \(- x\) ,那么前面离它最近的 \(+\) 的值可以设为 \(x\)

这个是为什么呢?

  • 首先对于连续的 \(-x\) ,那么后面的值一定比前面的小
  • 如果两段,假设第一段为 \(A\) 第二段设为 \(B\) 第三段设为 \(C\),那么如果 \(C\) 有一部分要在 \(AB\) 之间,那么可以确定的是 \(C\) 一定比 \(B\) 的值大,如果小,那么就是 NO。
    • 如果这部分被 \(C\) 占了,那么 \(B\) 的一部分就在 \(A\) 前面,说明 \(B\) 大于 \(A\)
    • 如果这部分被 \(B\) 占了,那么如果 \(B\) 可以往前推,那么 \(C\) 一定也可以往前推, \(C\) 大于 \(A\)

solution1

#include <bits/stdc++.h>
#define lson (id<<1)
#define rson (id<<1|1)
using namespace std;
const int maxn = 2e5 + 10;
/*
 * 单调栈维护 x,维护一个单调递减的
 * 线段树更新值,更新每一个位置 + 的数字
 */
int que[maxn],sum[maxn * 4],a[maxn],len[maxn * 4],r,ans[maxn];
void build(int id,int l,int r) {
    len[id] = r - l + 1, sum[id] = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(lson, l, mid);
    build(rson, mid + 1, r);
}
void update(int id,int l,int r,int pos) {
    if (pos < l || pos > r) return;
    if (l == r) {
        sum[id] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update(lson, l, mid, pos);
    else update(rson, mid + 1, r, pos);
    sum[id] = sum[lson] + sum[rson];
}
 
int modify(int id,int l,int r,int x,int y,int v) {
    if(x>r||y<l) return 0;
//    printf("modify:id = %d l = %d r = %d x = %d y = %d v = %d\n",id,l,r,x,y,v);
    if (l == r && sum[id] == 0) {
//        printf("l = %d r = %d\n",l,r);
        ans[l] = v,sum[id] = 1;
        return true;
    }
    int mid = (l + r) >> 1, ans = 0;
    if (x <= mid && sum[lson] < len[lson]) ans = modify(lson, l, mid, x, y,v);
    if (ans == 0 && y > mid && sum[rson] < len[rson]) ans = modify(rson, mid + 1, r, x, y,v);
    sum[id] = sum[lson] + sum[rson];
    return ans;
}
int ok(int x) {
    int lc = 1, rc = r, ans = 0;
    while (lc <= rc) {
        int mid = (lc + rc) >> 1;
        if (a[que[mid]] > x) lc = mid + 1, ans = que[mid];
        else rc = mid - 1;
    }
    return ans;
}
void debug(int id,int l,int r){
    if(l==r){
        printf("id = %d l = %d r = %d sum = %d\n",id,l,r,sum[id]);
        return ;
    }
    int mid = (l+r)>>1;
    debug(lson,l,mid);
    debug(rson,mid+1,r);
}
int main() {
    int n;
    scanf("%d", &n);
    build(1, 1, 2 * n);
    for (int i = 1; i <= 2 * n; i++) {
        char s[10];
        scanf("%s", s + 1);
        if (s[1] == '+') a[i] = -1;
        else scanf("%d", &a[i]), update(1, 1, 2 * n, i);
    }
    r = 0;
    que[r] = 0;
    bool flag = true;
    for (int i = 1; i <= 2 * n; i++) {
        if (a[i] > 0) {
            int pos = ok(a[i]) + 1;
            int res = modify(1, 1, 2 * n, pos, i,a[i]);
            if (!res) {
                flag = false;
                break;
            }
            while (r > 0 && a[i] >= a[que[r]]) r--;
            que[++r] = i;
        }
    }
    if(!flag) printf("NO\n");
    else {
        printf("YES\n");
        for(int i=1;i<=2*n;i++){
            if(a[i] < 0) printf("%d ",ans[i]);
        }
        printf("\n");
    }
}

solution2

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int ans[maxn];

int main(){
    int n;
    scanf("%d",&n);
    stack<int>sta;
    for(int i=1;i<=2*n;i++){
        char s[10];
        scanf("%s",s+1);
        if(s[1] == '+') sta.push(i);
        else{
            scanf("%d",&ans[i]);
            if(sta.empty()){
                printf("NO\n");
                return 0;
            }
            ans[sta.top()] = -ans[i];
            sta.pop();
        }
    }
    set<int>st;
    for(int i=1;i<=2*n;i++){
        if(ans[i] < 0) st.insert(-ans[i]);
        else{
            if(st.empty() || *st.begin() != ans[i]){
                printf("NO\n");
                return 0;
            }
            st.erase(st.begin());
        }
    }
    printf("YES\n");
    for(int i=1;i<=2*n;i++){
        if(ans[i] < 0) printf("%d ",-ans[i]);
    }
    printf("\n");
}
posted @ 2021-05-14 20:06  EchoZQN  阅读(75)  评论(0编辑  收藏  举报