2020牛客跨年赛部分题解

某位大佬说过,算法就是锻炼你的思维,通过下面这道题,确实暴露了我的智商
题目传送门
说一下正确的思路:通过例1发现,只要找到初始位置以及反转之后的位置,然后进行累加距离差就行。然而例2告诉我们另一种情况(如果没有给你说明例2,你会想到这种情况嘛),即一个数字出现多次。我们发现,最小花费其实就是距离差最小,所以当一个数字出现多次时,我们让原序列中排在前面的那个数字和反转序列中的最前的那个数字,这样就保证了距离差最小(比如有三个1,位置设为x2,x4,x6,反转之后序列为x9,x7,x5,这样我们肯定让x2与反转之后的x5进行操作,x4与x7)。更详细的在代码里面

#include<bits/stdc++.h>
using namespace std;
deque<int> d[100010];// 双端队列
int z[100010]; // 用来保存初始序列

int main()
{
	int n;
	int x;
    long long ans=0;  //  不要忘了 long long,爆了一次
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>z[i]; 
	for(int i=1;i<=n;i++)
	{
	   /* z[i]表示的是序列中i位置的那个数字
	   d[z[i]] 表示的相同数字出现的位置的集合,n-i+1,表示反转之后的位置
	   这里是加入到队首,因为反转之后的位置越来越小,加入队首保证了队首
	   是最小的位置,下面举例
	   1 1 2 3 1     a[i]  下标从1开始
	   1 3 2 1 1     反转之后
	   那么d[a[1]]=d[1]={5}  第一步
	      d[a[1]]=d[1]={2,5} 加入队首,这样就保证 
	       d[a[1]]=d[1]={1,2,5};
	   */
		d[z[i]].push_front(n-i+1);   
	}
	for(int i=1;i<=n;i++)
	{
	   /*
	    对于原序列的每一个数字,找出他反转之后的位置集合,找出队首那个,
	    因为队首那个最小,距离差最小
	  */
	    x=d[z[i]].front();
		d[z[i]].pop_front();   // 最小的出列
		ans+=abs(i-x);	  
	}
	   
	cout<<ans/2<<endl;   // 扫描原序列时每一个位置都算了两遍,所以除2
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值