【问题描述】
给定一个长度为m的序列a,下标编号为1~m。序列的每个元素都是1~n的
整数。定义序列的代价为Σa[i+1]-a[i]
你现在可以选择两个数x和y,并将序列a中所有的x改成y。x可以与y相等。
请求出序列最小可能的代价。
【输入格式】
输入第一行包含两个整数n和m。第二行包含m个空格分隔的整数,代表序列a。
【输出格式】
输出一行,包含一个整数,代表序列最小的代价。
【样例输入 1】
4 6
1 2 3 4 3 2
【样例输出 1】
3
【样例输入 2】
10 5
9 4 3 8 8
【样例输出 1】
6
【样例解释】
样例 1 中,最优策略为将 4 改成 3。样例 2 中,最优策略为将 9 改成 4。
【数据规模和约定】
60%的数据,n,m ≤ 2000。
对于100%的数据,1 ≤ n,m ≤ 100,000。
/* 这道题告诉我们,初中数学没学好是多么可怕的一件事~ 我们统计每个与i相邻的数grap[i],然后尽量使 Σ|grap[i]-i| 最小,那么我们就使i变成grap[i]的中位数(貌似结论很显然,然而我写的是平均数),然后对于每个i,去它们对答案贡献的最大值。 */ #include<cstdio> #include<iostream> #include<vector> #include<algorithm> #define N 100010 #define lon long long using namespace std; int a[N],m,n; vector<int> grap[N]; int main(){ freopen("note.in","r",stdin); freopen("note.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d",&a[i]); } for(int i=1;i<=m;i++){ if(i>1&&a[i]!=a[i-1])grap[a[i-1]].push_back(a[i]); if(i<m&&a[i]!=a[i+1])grap[a[i+1]].push_back(a[i]); } lon ans=0LL,sum=0LL; for(int i=1;i<=n;i++){ if(!grap[i].size())continue; sort(grap[i].begin(),grap[i].end()); int z=grap[i][grap[i].size()>>1]; lon qian=0LL,hou=0LL; for(int j=0;j<grap[i].size();j++){ qian+=(lon)(abs(i-grap[i][j])); hou+=(lon)(abs(z-grap[i][j])); } ans=max(ans,qian-hou);sum+=qian; } cout<<sum/2-ans; return 0; }