Description
箱子再分配问题需要解决如下问题:
(1)一共有N个物品,堆成M堆。
(2)所有物品都是一样的,但是它们有不同的优先级。
(3)你只能够移动某堆中位于顶端的物品。
(4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。
(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。
(6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本:
不会有两个物品有着相同的优先级,且M=2
题解:
显然方案是唯一的,所以直接模拟即可。我们可以把两堆合并成为一个数组,每次找到次大和最大的之间的距离,就是把最大删掉的代价。可以用树状数组实现。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=100010;
int n1,n2,n=0,s[maxn],a[maxn],b[maxn];
void add(int x,int y){for(int i=x;i<=n;i+=(i&-i))s[i]+=y;}
int getsum(int x){int re=0;for(int i=x;i;i-=(i&-i))re+=s[i];return re;}
struct node{int id,x;}A[maxn];
bool cmp(node x,node y){return x.x>y.x;}
int c[maxn],pos[maxn];
int main()
{
scanf("%d%d",&n1,&n2);
for(int i=n1;i;i--)scanf("%d",&a[i]),A[++n].id=i,A[n].x=a[i];
for(int i=1;i<=n2;i++)scanf("%d",&b[i]),A[++n].id=i+n1,A[n].x=b[i];
sort(A+1,A+1+n,cmp);
for(int i=1;i<=n;i++)c[A[i].id]=i,pos[i]=A[i].id;
for(int i=1;i<=n;i++)s[i]=(i&-i);
LL ans=0;
pos[0]=n1;//pos[0]存的是栈顶
for(int i=1;i<=n;i++)
{
LL last=ans;
int p2=pos[i-1],p1=pos[i];
if(p1>p2)ans+=(LL)(getsum(p1-1)-getsum(p2));
else ans+=(LL)(getsum(p2)-getsum(p1));
add(pos[i],-1);
}
printf("%lld",ans);
}