链接:http://codeforces.com/problemset/problem/433/C
思路:可以先计算总的消耗,接着计算将某一类型的所有数字更换成相邻的数字之后所降低消耗的最大值。。
可以枚举每一个数换成相邻的数字之后减低的消耗,正常枚举肯定会超时。所以需要我们先求出每一个相邻数字的前缀和,接着枚举一个可以用o(1)的时间算出降低的消耗,具体看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll>v[100005];
map<int,int>ma;
map<int,int>::iterator it;
int a[100005];
ll rem[100005];
int main()
{
int n,m;
ll res=0,temp=0;
scanf("%d%d",&n,&m);
for(int i=0;i<100005;i++)
v[i].clear();
ma.clear();
for(int i=1;i<=m;i++)
{
scanf("%d",a+i);
if(i!=1)
res+=fabs(a[i]-a[i-1]); //先求出总的消耗
ma[a[i]]++;
}
for(int i=1;i<=m;i++) //相邻的数字压入邻接表 相同数字就没有必要了
{
if(i!=1&&a[i-1]!=a[i])v[a[i]].push_back(a[i-1]);
if(i!=m&&a[i+1]!=a[i])v[a[i]].push_back(a[i+1]);
}
ll r=0;
for(it=ma.begin();it!=ma.end();it++)
{
int i=it->first;
int t=v[i].size();
if(t==0)continue;
sort(v[i].begin(),v[i].end()); //求前缀和前先排序
rem[0]=v[i][0];
temp=fabs(v[i][0]-i);
for(int k=1;k<t;k++)
{
rem[k]=rem[k-1]+v[i][k];
temp+=fabs(v[i][k]-i);
}
ll tem=0,ans=0;
for(int k=0;k<t;k++) //接着枚举每一个相邻数字
{
tem=rem[t-1]-rem[k]-(ll)(v[i][k]*(t-k-1))+(ll)(v[i][k]*(k+1))-rem[k];
if(temp-tem>ans)
ans=temp-tem;
}
r=max(r,ans);
}
printf("%lld\n",res-r);
return 0;
}