码迷,mamicode.com
首页 > 其他好文 > 详细

洛谷 P3253 [JLOI2013]删除物品 解题报告

时间:2018-05-20 21:27:18      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:efi   algo   接下来   void   翻转   code   分配   int   题解   

P3253 [JLOI2013]删除物品

题目描述

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

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

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

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

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

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

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

输入输出格式

输入格式:

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

输出格式:

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

说明

\(1<=N1+N2<=100000\)


说一下我做这个题的心路历程。

  1. 汉诺\(n\)塔问题?
  2. 两个栈?
  3. 等等,我似不似看错了,这不就是个模拟???
  4. 好像没错啊...
  5. 噫?模拟是\(O(n^2)\)?
  6. 苟不住了估计要跑数据结构
  7. 噫,我把这一坨挪到另一个上面后它们距离当前栈顶的距离是翻转区间???
  8. 分......分块?完了不会分块啊
  9. 瞎画+摸鱼\(ing\)
  10. 等等,我把两个栈bu~成一个数组后不仅只用挪中间的断点了
  11. 这样我拿线段树维护一下某点左边后几个被巴拉掉了
  12. 等等,咋不对啊。模拟一下,然后我发现做断点左边的点时要额外减去1...
    最后,瞅了瞅题解。这个..别人都维护的是元素个数啊。。

做的还是有点小麻烦的。。。


code:

#include <cstdio>
#include <algorithm>
#define ls id<<1
#define rs id<<1|1
#define mid (l+r>>1)
#define R (t[id].r)
#define L (t[id].l)
#define Mid (L+R>>1)
using namespace std;
const int N=100010;
int a[N],di,n;
struct node2
{
    int i,w;
    bool friend operator <(node2 n1,node2 n2)
    {
        return n1.w>n2.w;
    }
}b[N];
struct node
{
    int l,r,w,lazy;
}t[N*4];

void build(int id,int l,int r)
{
    L=l,R=r;
    if(l==r) return;
    build(ls,l,mid);
    build(rs,mid+1,r);
}

void change(int id,int l,int r)
{
    if(L==l&&R==r)
    {
        t[id].lazy-=1;
        return;
    }
    t[id].w-=(r+1-l);
    if(r<=Mid)
        change(ls,l,r);
    else if(l>Mid)
        change(rs,l,r);
    else
    {
        change(ls,l,Mid);
        change(rs,Mid+1,r);
    }
}

void push_down(int id)
{
    t[id].w+=t[id].lazy*(R+1-L);
    if(L!=R)
    {
        t[ls].lazy+=t[id].lazy;
        t[rs].lazy+=t[id].lazy;
    }    
    t[id].lazy=0;
}

int query(int id,int loc)
{
    push_down(id);
    if(L==R)
        return t[id].w;
    if(loc<=Mid)
        return query(ls,loc);
    else
        return query(rs,loc);
}
long long ans=0;
int main()
{
    int n1,n2;
    scanf("%d%d",&n1,&n2);
    for(int i=n1;i>=1;i--)
        scanf("%d",a+i);
    di=n1;n=n1+n2;
    for(int i=1;i<=n2;i++)
        scanf("%d",a+i+n1);
    for(int i=1;i<=n;i++)
        b[i].i=i,b[i].w=a[i];
    sort(b+1,b+1+n);
    build(1,1,n);
    int now=b[1].i;
    ans+=abs(now-di);
    if(now>di) ans--;
    di=now;
    if(now!=n) change(1,now+1,n);
    for(int i=2;i<=n;i++)
    {
        now=b[i].i;
        int q1=query(1,now),q2=query(1,di);
        ans+=abs(now+q1-di-q2);
        if(now<di) ans--;
        if(now!=n) change(1,now+1,n);
        di=now;
    }
    printf("%lld\n",ans);
    return 0;
}

2018.5.20

洛谷 P3253 [JLOI2013]删除物品 解题报告

标签:efi   algo   接下来   void   翻转   code   分配   int   题解   

原文地址:https://www.cnblogs.com/ppprseter/p/9064473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!