Codeforces RoundC. Ryouko's Memory Note

题目意思:给一组序列,找到一个点,变成另外一个点,使这个序列左右之间的绝对值之和最小。


列出一个vector数组,每个保存该点相邻的数(与本点相同的不保存),然后查找每个点,令该点与vector内相邻的数的中位数相交换,得到最小的和。


与中位数交换的原因:假设有十个点,我们取第7个点为当前点,现在换到第6个点,第7点与第6点距离为d,那么1-6点距离和减少6d,7-10点距离和增加4d,总共的距离和减少了2d,以此类推,即处在中间位置的点与各个点的距离和最小。若序列为偶数1,2,……n,n+1,……,2n,那么在n~n+1之间任意取点与各个点距离最小,若序列为奇数,1,2,……,n,则在n/2+1处取点各个点距离最小。


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int n,m;
	vector<long long > a[100005];
	scanf("%d%d",&n,&m);
	long long num[100005];
	int maxn = 0;
	for(int i=0;i<m;i++){
		scanf("%I64d",&num[i]);
		if(maxn<num[i]){
			maxn = num[i];
		}
	}
	long long sum = 0;
	for(int i=1;i<m;i++){
		if(num[i-1]!=num[i]){
			sum += abs(num[i-1]-num[i]);
			a[num[i-1]].push_back(num[i]);
			a[num[i]].push_back(num[i-1]);
		}
	}
	long long result = sum;
	for(int i=1;i<=maxn;i++){
		long long temp = sum;
		int l = a[i].size();
		if(l!=0){
			sort(a[i].begin(),a[i].end());	//中位数正确 
			int mid = a[i][l/2];
			/*int mid = 0;				//平均数错误 
			for(int k = 0;k<l;k++){
				mid += a[i][k];
			}

				mid/=l;
			*/
			for(int j=0;j<l;j++){
				temp = temp + abs(mid-a[i][j]) - abs(i-a[i][j]);
			}
		}
		result = min(result,temp);
	}
	printf("%I64d\n",result);
	return 0;
}


你可能感兴趣的:(Math,codeforces)