zoukankan      html  css  js  c++  java
  • 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
    ",id,l,r,x,y,v);
        if (l == r && sum[id] == 0) {
    //        printf("l = %d r = %d
    ",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
    ",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
    ");
        else {
            printf("YES
    ");
            for(int i=1;i<=2*n;i++){
                if(a[i] < 0) printf("%d ",ans[i]);
            }
            printf("
    ");
        }
    }
    

    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
    ");
                    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
    ");
                    return 0;
                }
                st.erase(st.begin());
            }
        }
        printf("YES
    ");
        for(int i=1;i<=2*n;i++){
            if(ans[i] < 0) printf("%d ",-ans[i]);
        }
        printf("
    ");
    }
    
  • 相关阅读:
    [置顶] java得到前一个月的年月日时分秒
    Windows 8.1 Preview的新功能和新API
    oracle保证读一致性原理
    10161
    Qt国际化
    使用Maven管理依赖JAR文件,自定义项目布局,利用ANT生成不同的发布包
    Haxe2.10到Haxe3,NME到OpenFL的迁移备忘
    设置RichEdit相关颜色说明
    使用MFC CImage类绘制PNG图片时遇到的问题
    把网球计分招式重构到状态模式
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14769771.html
Copyright © 2011-2022 走看看