——我觉得新人的痛处就是看不懂大佬们的题解。而同样作为新人的我对此表示深切的理解和遗憾,正因为如此我用形象的事情比喻了这个题的解法,希望能帮助您解决这道题。我不是打oi出身的,我懂得算法也不是很多,我没法把它打上“贪心”或者“dp”的标签,我也说不清它是什么。但我觉得我们可以形象化地去理解一些事情。
——我们将题目换一种方式想:我们不再想象去牛牛去传递星星,而是在一个水平线上,有高高低低的土堆,且每个土块都是方形的;这就造就了许多方形的坑,我们需要把这个高高低低不平的坑推平。那么之前问题的牛牛传递星星的最少次数,就是这些土方块的水平移动的距离的最小的和——因为一个位置的土块要填补到另一个位置,就相当于原问题里牛牛的星星被传递到某个位置。只是我们必须认为这个水平的场景两边都有“结界”,土块可以被推土机推着穿过结界从最右穿到最左。
——以题目给出的样例为例。
示意图1:(推土机未在示意图中表示出)

结界:|
土块:0
空气:·

|··0·|
|··0·|
|··00|
|··00| 
 ---- 我是填满之后的水平线
|··00| 
|··00|
|·000|
|·000|

——解决问题的关键来了:我们想象有一个推土机,它会在预先填满的水平线上行走。我们不妨假设这个推土机从最左端开始走。如果土高于填满之后的水平线,那么推土机就会获得高出的那部分土,如果土比填满之后的水平线矮,那么推土机就会尽可能释放手里的土——为了便于考虑,我们不妨认为推土机手里没有土的时候它就会直接过去而不会放下土。这样的话,当推土机遍历整个地区一次,从结界的另一边穿出来的时候,或许还会留下一些坑,但是肯定没有高过填满之后的水平线的土堆了。因此我们再遍历一遍整个地区,我们就完成了填坑这项工作。
示意图2:此时,推土机穿过结界后跑到最左端,手里有6个土块(推土机未在示意图中表示出)

|····|
|····|
|····|
|····| 
 ---- 我是填满之后的水平线
|··00| 
|··00|
|·000|
|·000|

示意图3:推土机又经过一次整个地区,将坑填满(推土机未在示意图中表示出)

|····|
|····|
|····|
|····| 
 ---- 我是填满之后的水平线
|0000| 
|0000|
|0000|
|0000|

——当然如果你开心的话,你也可以规定这个推土机在第一遍经过时只拿起土堆,第二遍经过的时候只放下。
——我们不妨将相邻两个格(包括最前和最后穿过结界)之间称作路。于是,推土机在路上携带土块经过的时候,因为推土机上的土移动了,这就意味着这条路上有了一个“消耗能量”或者像“做功”的过程,并且路上之间的“做功”就是路上经过的这些土块的值,并且这个“做功”的过程都是从左向右(或穿过右边结界)的。于是这两遍下来,所有的路上都有一个为正数的“做功”的值。我们认为向右(或穿过右边结界)做功记作整数,反之记作负数。
——根据推土机推过两遍的这个过程,我们得到了一个因为运送土堆消耗的“能量值”。我们发现这个过程所消耗的能量的绝对值还是太大。怎么办呢?
——我们注意到这个路上往往有很多路都是从左往右运输土,甚至有很多时候,这些土穿过了结界回到原来的地方——这意味着它转了大半圈或者整个圈。更普遍地是,有若干些土在不同的地方以不相交地路径各自从左到右(或穿过右边结界)经过了大半的路并到达他们各自的填充位置,那么我们不如让这些土以不相交地路径从右到左(或穿过左边结界)经过了小半的剩下的路到达这些原来这些填充位置(注意!每个点或许不会再跑到原来的各自的填充位置了,但总体来讲,还是这些坑)。因此根据上边这个策略,最优的情况肯定不会有超过一半的路是从左往右且不会有超过一半的路从右往左。对应在数学上,就是将这些数全部减小/增加相同的数字,使得负数和正数各不超过一半。于是我们想到中位数,然后令所有路径上的有符号的“做功”值减掉这些的中位数,得到了一些新的“做功”的值,将这些做功的值按绝对值相加,得到了总共消耗的最小“能量”,即题目的答案。
核心代码(Java):

//数据读入
int n=ir.nextInt();
long[] a=new long[n];
long[] b=new long[n];
for(int i=0;i<n;i++) {
    a[i]=ir.nextLong();
}
//计算平均高度,并按照平均高度减去
long sum=0;
for(int i=0;i<n;i++) {
    sum+=a[i];
}
long ave=sum/n;
for(int i=0;i<n;i++) {
    a[i]-=ave;
}
//推土!
long dirtInHand=0;
for(int i=0;i<2*n;i++) {
    if(a[i%n]+dirtInHand>=0) {
        dirtInHand+=a[i%n];
    a[i%n]=0;
    }
    b[i%n]+=dirtInHand;
}
//寻找中位数
Arrays.sort(b);
long mid=b[n/2];
//减去中位数
for(int i=0;i<n;i++) {
    b[i]-=mid;
}
//计算和输出答案
long ans=0;
for(int i=0;i<n;i++) {
    ans+=(b[i]>0?b[i]:-b[i]);
}
System.out.println(ans);