C. Ryouko's Memory Note
题意: 给m 个数,0<ai<=n; 改变一个数(如果 aj==ai ,改变ai= c,那么 aj也会为 c ) 使得相邻的距离和最小;
思路: 把ai 相邻的数加入 ai 的 的点集中,当ai 等于这个点集的中位数时,ai 到这个点集的距离是最小的;
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<set>
#include<queue>
#include<map>
#include<vector>
using namespace std;
int n,m;
int a[1000100];
bool vis[100100];
long long old[100100];
vector<int>e[100100];
long long ans,sum;
void build(){
for(int i=1;i<=n;i++) e[i].clear();
memset(old,0,sizeof(old));
for(int i=1;i<=m;i++){
if(a[i-1]!=a[i]) e[a[i]].push_back(a[i-1]);
if(a[i+1]!=a[i]) e[a[i]].push_back(a[i+1]);
old[a[i]]+=abs(a[i]-a[i+1]);
old[a[i]]+=abs(a[i]-a[i-1]); // old[] 数组维护的是 ai 这个点集原先的距离和;
}
}
void work(){
for(int i=1;i<=n;i++){
if(old[i]==0) continue; //这个数不存在的情况;
sort(e[i].begin(),e[i].end());
int mid=(e[i].size()+1)/2-1;
mid=e[i][mid]; //mid 为中位数
if(mid==i) continue; // I 本身就是中位数的情况;
vector<int>::iterator it;
long long tp=0;
for(it=e[i].begin();it!=e[i].end();it++){
tp+=abs(mid-*it);
}
if(tp<old[i]) ans=min(ans,sum-old[i]+tp);
}
}
int main()
{
// freopen("in.in","r",stdin);
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=m;i++) scanf("%d",&a[i]);
sum=0;a[0]=a[1];a[m+1]=a[m];
for(int i=1;i<m;i++) sum+=abs(a[i+1]-a[i]);
build();
ans=sum;
work();
cout<<ans<<endl;
}
return 0;
}