CCA的搬运

题目链接:nowcoder 217041

到主站看:https://blog.csdn.net/weixin_43346722/article/details/115219135

题目大意

一个洞中有 n 个质量的球,要进行一些操作,每次把一个求拿出来放到最上面。
拿的费用是它上面小球质量和。
给出每次要拿的小球的编号,问你找到一种初始球的位置方案,使得花费体力最小。

思路

首先我们考虑怎么让体力最小。

那既然每次会把球放到最上面,那我们就会发现,它上面至少会有的球是它上一次放到最上面到现在放到上面的球。
就比如序列是:,那第二次把 放上去的时候,它的前面就至少会有

那我们要让花费体力最小,就尽可能让它的前面除了这些东西不再有别的。
那构思就出来了,如果这个要上提的球之间没有见过,就把它放在现在一直序列的最后面,然后再提到最前面。
如果之前见过,那我们就把它提到最前面。

那如果一直没有见过,就把它们放在最最后面。(顺序无所谓,因为它们的后面都不会有要提上去的点,都不会对总费用产生贡献)

然后因为可以 ,那我们上移就直接模拟,一个一个的替换,往上跳就可以过了。

代码

#include<cstdio>
#include<algorithm>
#define ll long long 

using namespace std;

int n, m, a[2001], sum;
int xx[2001], now;
bool nd[2001];
ll ans;

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

    for (int i = 1; i <= m; i++) {
        scanf("%d", &now);
        if (!nd[now]) {
            nd[now] = 1;
            ans += 1ll * sum;//把它放在最下面,那移动的费用就是上面所有球的质量和
            sum += a[now];
            xx[++xx[0]] = now;
            for (int j = xx[0] - 1; j >= 1; j--)//移到最上面
                swap(xx[j], xx[j + 1]);
        }
        else {
            for (int j = xx[0]; j >= 1; j--)
                if (xx[j] == now) {
                    for (int k = j - 1; k >= 1; k--) {//移到最上面
                        ans += 1ll * a[xx[k]];//统计移上去的费用
                        swap(xx[k], xx[k + 1]);
                    }

                    break;
                }
        }
    }

    printf("%lld", ans);

    return 0;
}