<题目链接>
题目大意:
给你一堆数字,允许你修改所有相同的数字成为别的数字,不过只能修改一次,问你修改后序列相邻数字的距离和最小是多少。
解题分析:
首先,修改不是任意的,否则那样情况太多了,因为最后只是求序列相邻项差值的绝对值的和,所以我们只需要考虑修改之后能够改变最终答案的情况,因为本题要使差值的绝对值的和最小,所以我们可以利用中位数的性质转化。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N int(1e5+7) 5 typedef long long ll; 6 vector<int>G[N]; 7 int n,m,a[N]; 8 9 int main(){ 10 scanf("%d%d",&n,&m); 11 ll res=0; 12 for(int i=1;i<=m;i++){ 13 scanf("%d",&a[i]); 14 if(i>1 && a[i]!=a[i-1]){ //因为没有必要将相同页数的进行merge 15 G[a[i]].push_back(a[i-1]),G[a[i-1]].push_back(a[i]); //如果第i条信息所在页merge为其它页能够造成最终结果改变,就将它们连边,等一下会进行这些情况的考虑 16 res+=abs(a[i]-a[i-1]); //得到初始的差值绝对值之和 17 } 18 } 19 ll ans=res; 20 for(int i=1;i<=n;i++){ 21 ll sz=G[i].size(); 22 if(sz){ 23 ll tmp=res; 24 sort(G[i].begin(),G[i].end()); 25 int mid=G[i][sz/2]; //第i页改为要必要更改的页码(更改后能对最终的结果造成改变的页码)中的中位数 26 for(int j=0;j<sz;j++)tmp+=abs(mid-G[i][j])-abs(i-G[i][j]); //根据中位数的性质,mid-G[i][j]之和,必然小于等于i-G[i][j]之和 27 ans=min(ans,tmp); 28 } 29 } 30 printf("%lld ",ans); 31 }
2019-02-22