【nowcoder 217041】CCA的搬运

CCA的搬运

题目链接:nowcoder 217041

到牛客看:

——>点我跳转<——

题目大意

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

思路

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

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

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

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

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

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/115219135