题目描述
箱子再分配问题需要解决如下问题:
(1)一共有N个物品,堆成M堆。
(2)所有物品都是一样的,但是它们有不同的优先级。
(3)你只能够移动某堆中位于顶端的物品。
(4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。
(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。
(6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本: 不会有两个物品有着相同的优先级,且M=2
输入输出格式
输入格式:
第一行是包含两个整数N1,N2分别表示两堆物品的个数。接下来有N1行整数按照从顶到底的顺序分别给出了第一堆物品中的优先级,数字越大,优先级越高。再接下来的N2行按照同样的格式给出了第二堆物品的优先级。
输出格式:
对于每个数据,请输出一个整数,即最小移动步数。
输入输出样例
输入样例#1: 复制
3 3 1 4 5 2 7 3
输出样例#1: 复制
6
说明
1<=N1+N2<=100000
思路:很有意思的一道题,思路倒是不怎么难,不过在过程的实现中稍微出了点偏差,在这里我们需要使用一个数组来模拟俩个栈,其次的话使用离散化,因为他没有给定数据的范围,接下来就是树状数组的运用,在这里我们每次记录第一个栈的最顶端的下标为left,当前最大值的下标为index,那么我们pop的过程中就是对index与left的进行分析,若是index比left大,说明最大值在第二个栈中,那么我们需要用数组中该最大数左边的数的个数减去第一个栈中元素的个数,然后更新树状数组,若是index《=left,说明最大值在第一个栈中,需要pop的数目就是该栈内元素的个数到该最大值的差值,然后更新树状数组,之前我就是没有更新树状数组导致翻车了很久,下面直接看代码
#include<iostream>
#include<algorithm>
using namespace std;
#define lowbit(i) ((i)&(-i))
const int maxn = 100010;
int n, m;
int leftNum[maxn], c[maxn], a[maxn];
struct Node {
int val, pos;
}node[maxn];
int cmp(Node a, Node b) {
return a.val > b.val;
}
void update(int x, int v) {
for (int i = x; i < maxn; i += lowbit(i)) {
c[i] += v;
}
}
int getSum(int x) {
int sum = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
sum += c[i];
}
return sum;
}
int main() {
cin >> n >> m;
for (int i = n; i >= 1; i--) {
cin >> a[i];
}
for (int i = n + 1; i <= n + m; i++) {
cin >> a[i];
}
for (int i = 1; i <= n + m; i++) {
node[i].val = a[i];
node[i].pos = i;
update(i, 1);
}
//排序
sort(node + 1, node + 1 + n + m, cmp);
int left = n;
long long ans = 0;
for (int i = 1; i <= n + m; i++) {
int index = node[i].pos;//最大值的下标
if (index > left) {
ans += getSum(index - 1) - getSum(left);
left = index - 1;
update (index, -1);//更新树状数组,也就是删除该数
} else {
ans += getSum(left) - getSum(index);
update(index, -1);//更新
left = index - 1;
}
}
cout << ans << endl;
}