题意:给出一个栈中的礼物,编号为1~n,顶部编号为a1,接下来为a2,底部为an,每个编号唯一,给出一个发送礼物的清单,编号为b1,b2,...bn,必须按编号顺序发送礼物,每次发送礼物,从栈中寻找礼物,要想拿走这个礼物,必须先拿走这个礼物前面k个礼物,所花费时间为2k + 1秒,并且重新放回栈中,但是我们可以重新排序好后放回栈中,问我们发送清单的礼物所需要花费的最短时间?
分析:我们可以记录从开始到现在寻找礼物所能到达的最大深度,那么栈中当前需要寻找的礼物上面的礼物都可以摆放一个最优的顺序,使得接下来需要拿的礼物直接可以从栈顶上拿走,所需时间即为1s,
如果现在所要找的礼物的深度大于最大深度,我们就可以更新最大深度,并且求出pos[b[i]] - i(该礼物在栈中位置和顶部之差)。
总结:对于一些涉及到位置关系的问题,我们可以开一个Pos数组,记录每个数字所在的位置
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 100005;
int Pos[N];
int a[N], b[N];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
//栈中礼物,要发送的礼物数量
int n, m;
scanf("%d%d", &n, &m);
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
Pos[a[i]] = i;
}
for (int i = 1; i <= m; ++i)
{
scanf("%d", &b[i]);
}
//记录可以拿到的最大位置
int mPos = -1;
LL res = 0;
for (int i = 1; i <= m; ++i)
{
//之前可以到大的最深位置大于现在该礼物的位置,说明之前的礼物可以排序
//排序后的下一个礼物可以放置在最顶端
if (Pos[b[i]] < mPos)
++res;
else
{
//现在的位置减去拿走礼物的数量
res += (Pos[b[i]] - i) * 2;
++res;
//可以更新最大位置
mPos = Pos[b[i]];
}
}
printf("%lld
", res);
}
return 0;
}