原题链接
思路:
对于压在栈 \(a\) 最底下的礼物 \(a_n\), 若 \(a_n\) 是所需要的礼物之一,
则可把数组 b 分为两部分:
对于交付时间在 \(a_n\) 前的礼物,
未排序并且已经拿走.
对于交付时间在 \(a_n\) 后的礼物,
已排序,花费时间为 1.
所以对于 \(a_n\), 设 \(a_n\) 为第 \(x\) 件取出的物品,则取出 \(a_n\) 所需要的时间为:
\[ 2(n-1-(x-1))+1 = 2(n-x)+1 \]
根据这个公式可以设计出算法:
对栈 \(a\) 从底向顶遍历,设第 \(o_i\) 个礼物为 \(a_i\), \(o_{min,i}\) 为区间 \((i,n]\) 中最小的 \(o_i\), 则取出 \(a_i\) 所需的时间:
\[
t_i = \begin{cases}
2(i-o_i)+1 &,\text{$o_i<o_{min,i}$} \\
1 &,\text{$o_i>o_{min,i}$}
\end{cases}
\]
答案即为 \(t_i\) 之和.
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include <cstdio> #include <cstring> const int Mn(100500); int ax[Mn],tbx[Mn]; int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d %d",&n,&m); memset(tbx,0,sizeof tbx); for(int i(1);i<=n;++i) scanf("%d",ax+i); for(int i(1);i<=m;++i) { int x; scanf("%d",&x); tbx[x] = i; } long long ans(0); int mn(m+1); for(int i(n);i;--i) { if(tbx[ax[i]]) { if(tbx[ax[i]]<mn) { mn=tbx[ax[i]]; ans+=2*(i-tbx[ax[i]])+1; } else ++ans; } } printf("%lld\n",ans); } return 0; }
|