zoukankan      html  css  js  c++  java
  • 删除物品[JLOI2013]

    ——JLOI2013(bzoj3192)

    删除物品

    题目描述

    箱子再分配问题需要解决如下问题:

    (1)一共有N个物品,堆成M堆。

    (2)所有物品都是一样的,但是它们有不同的优先级。

    (3)你只能够移动某堆中位于顶端的物品。

    (4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。

    (5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。

    (6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本: 不会有两个物品有着相同的优先级,且M=2

    输入格式

    第一行是包含两个整数N1,N2分别表示两堆物品的个数。接下来有N1行整数按照从顶到底的顺序分别给出了第一堆物品中的优先级,数字越大,优先级越高。再接下来的N2行按照同样的格式给出了第二堆物品的优先级。

    输出格式

    对于每个数据,请输出一个整数,即最小移动步数。

    输入

    3 3
    1
    4
    5
    2
    7
    3
    

    输出

    6
    

    说明

    $1<=N_1+N_2<=100000 $

    解析

    看完题应该有思路了,但纯模拟肯定是不行的,要用数据结构,用什么?

    是的,确实用线段树/树状数组,但是用线段树统计啥?

    这道题大体思路是这样的:将两堆物品头对头连起来,形成一列,想象中间有个挡板,移动物品相当于移动挡板。用0和1标记每个物品,表示这个物品取过还是没取过。移动挡板,扫过的0/1的和就是移动的步数对吧。把一个物品从1改成0是单点修改,统计扫过面积的和是区间查询,就用树状数组或线段树了。

    我的代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 100005;
    typedef long long ll;
    ll nn[maxn];
    ll fake[maxn];
    ll tree[maxn<<2];
    ll lazy[maxn<<2];
    int n1,n2;
    struct seq
    {
        int id,v;
    };
    seq num[maxn];
    bool cmp(seq a,seq b)
    {
        return a.v > b.v;
    }
    void pushup(int o)
    {
        tree[o] = tree[o<<1] + tree[o<<1|1];
    }
    void build(int o,int l,int r)
    {
        if(l == r)
        {
            tree[o] = nn[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void modify(int pos,int w,int l,int r,int o)
    {
        if(l == r)
        {
            tree[o] = w;
            return;
        }
        int mid = (l + r) >> 1;
        if(mid >= pos)
            modify(pos,w,l,mid,o<<1);
        else
            modify(pos,w,mid+1,r,o<<1|1);
        pushup(o);
    }
    void lazydown(int o,int ln,int rn)
    {
        if(lazy[o] != 0)
        {
            lazy[o<<1] += lazy[o];
            lazy[o<<1|1] += lazy[o];
            tree[o<<1] += lazy[o] * ln;
            tree[o<<1|1] += lazy[o] * rn;
            lazy[o] = 0;
        }
    }
    int query(int L,int R,int l,int r,int o)
    {
        if(L <= l && r <= R)
        {
            return tree[o];
        }
        int mid = (l + r) >> 1;
        lazydown(o,mid-l+1,r-mid);
        ll ans = 0;
        if(L <= mid)
            ans += query(L,R,l,mid,o<<1);  
        if(R > mid)
            ans += query(L,R,mid+1,r,o<<1|1);  
        return ans;
    }
    int main()
    {
        ll ans = 0;
        scanf("%d%d",&n1,&n2);
        for(int i=1;i<=n1;i++)
            scanf("%lld",&fake[i]);
        reverse(fake+1,fake+n1+1);
        for(int i=n1+1;i<=n1+n2;i++)
            scanf("%lld",&fake[i]);
        for(int i=1;i<=n1+n2;i++)
        {
            num[i].id = i;
            num[i].v = fake[i];
        }
        memset(nn,1,n1+n2+1);
        int pointer = n1;
        for(int i=1;i<=n1+n2;i++)
            nn[i] = 1;
        build(1,1,n1+n2);
        sort(num+1,num+n1+n2+1,cmp);
        for(int i=1;i<=n1+n2;i++)
        {
            int p; bool mmp = 0;
            int temp = num[i].id;
            if(pointer > temp)
            {
                swap(pointer,temp);
                p = pointer - 1;
            }
            else
            {
                mmp = 1;
                p = pointer + 1;
            }
            modify(num[i].id,0,1,n1+n2,1);
            ans += query(pointer,temp,1,n1+n2,1);
            if(mmp == 1)
                pointer = temp;
        }
        printf("%lld",ans);
        return 0;
    }
    

    不要参考我的代码……我的代码样例没过,竟然就A了……

  • 相关阅读:
    HDU 3466(01背包变种
    HDU 2639(01背包第K大)
    POJ 2184(01背包)(负体积)
    UVA 562(01背包)
    UVA 624(01背包记录路径)
    SQL总结二
    oracle--知识点汇总1
    时间日期----java
    字符串、数值----转换
    字符串反转----示例
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/9478732.html
Copyright © 2011-2022 走看看