Codeforces 433C #248_div1_A 中位数的应用

擦。。今天这套题好尼玛难啊,做了一个小时,连一题都没做出来,而且还没什么头绪

查了下出题人,师大附中的 14年毕业 13年拿到的国家集训队资格 保送清华

题意是 给一串序列,计算一个值,这个值是 相邻两数的距离(或者说差的绝对值)的总和,你可以改变任意一种数(即序列里所有该数字全部变成另一个数),但只能改一次,使得刚刚要求得那个值最小。

要是只改一个数,那就很简单了,但是这个题是要改一种数,序列式乱序的,所求值跟相邻数有关,所以又不能随便打乱顺序。

然后就疯狂抓头。。

后来还是看的题解

其实题目里面改变一种数其实也很好处理,把该种数的相邻的数字都给存起来,然后就是看该数字跟这些m个数(假设为m个)的距离的最小了。根据以前数轴的思想,不难得出,只要把当前该x值,变成排序过后的m个数列中的中位数即可。因为中位数的性质就是跟所有序列数的距离和最小,这个用数轴思想很容易证明。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define LL __int64
using namespace std;
const int N = 100000+10;
int A[N];
int n,m;
int vis[N];
vector<int> v[N];
int abs(int x)
{
    if (x<0) return -x;
    else return x;
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        LL ans=0;
        memset(vis,0,sizeof vis);
        for (int i=1;i<=m;i++){
          scanf("%d",&A[i]);
          if (i>1){
            if (A[i]!=A[i-1]){
                v[A[i]].push_back(A[i-1]);
                v[A[i-1]].push_back(A[i]);
            }
            ans+=(LL)abs(A[i]-A[i-1]);
          }
        }
        LL maxn=0;
        if (m>1)
        for (int i=1;i<=m;i++){
            if (vis[A[i]]) continue;
            vis[A[i]]=1;
            sort(v[A[i]].begin(),v[A[i]].end());
            int r=v[A[i]].size();
            if (r==0) continue;
            r/=2;
            int mid=v[A[i]][r];
            LL t1=0;
            LL t2=0;
            for (int j=0;j<v[A[i]].size();j++){
                t1+=(LL)abs(mid-v[A[i]][j]);
            }
            for (int j=0;j<v[A[i]].size();j++){
                t2+=(LL)abs(A[i]-v[A[i]][j]);
            }
            maxn=max(maxn,t2-t1);
        }
        ans-=maxn;
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kkrisen/p/3818697.html