bzoj 3192: [JLOI2013]删除物品

3192: [JLOI2013]删除物品

Description

箱子再分配问题需要解决如下问题:
 (1)一共有N个物品,堆成M堆。
 (2)所有物品都是一样的,但是它们有不同的优先级。
 (3)你只能够移动某堆中位于顶端的物品。
 (4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。
(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。
 (6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本:
         不会有两个物品有着相同的优先级,且M=2

Input

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

Output

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

Sample Input

3 3
1
4
5
2
7
3

Sample Output

6

HINT

1<=N1+N2<=100000

题解:

一开始没啥思路,但可以确定这题就是个模拟。。

刚开始就是卡在了元素的移动上。。

突然发现把第一组数倒着输入,后一组正着,把顶放在中间,移动的问题就完美解决了。。

比如样例,数组中存5 4 1 2 7 3

移动就是改变分割点,整个操作用树状数组实现。

 

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
struct node
{
    int a,id;
}p[N];
int n,m,x,a[N],t[N];
long long ans;
inline void read(int &v){
    char ch,fu=0;
    for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
    if(ch=='-') fu=1, ch=getchar();
    for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
    if(fu) v=-v;
}
int solve(int x)
{
    int ans=0;
    while(x)
    {
        ans+=t[x];
        x-=x&-x;
    }
    return ans;
}
void update(int x,int y)
{
    while(x<=n+m)
    {
        t[x]+=y;
        x+=x&-x;
    }
}
bool cmp(const node&x,const node&y)
{
    return x.a>y.a;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=n;i>=1;i--) read(p[i].a),p[i].id=i;
    for(int i=n+1;i<=n+m;i++) read(p[i].a),p[i].id=i;
    sort(p+1,p+n+m+1,cmp);
    for(int i=1;i<=n+m;i++) update(i,1);
    x=n;
    for(int i=1;i<=n+m;i++)
    {
        if(p[i].id>x) ans+=solve(p[i].id-1)-solve(x);else
        ans+=solve(x)-solve(p[i].id);
        update(p[i].id,-1);
        x=p[i].id;
    }
    cout<<ans;
    return 0;
}

 

 

posted @ 2016-07-13 18:14  lwq12138  阅读(480)  评论(0编辑  收藏  举报