UVa 11300打卡

算法入门经典训练指南打卡

题目链接:UVa 11300

思路

举个栗子:设现在有四个人,第i人给上一个人的金币和收到上一个人的金币的和为xi,如图:
在这里插入图片描述
由上图可知:

对于A1:M = A1 - x1 + x2 --> x2 - x1 = M - A1 = -C1 --> x2 = x1 - C1
对于A2:M = A2 - x2 + x3 --> x3 - x2 = M - A2 = -C2 --> x3 = x1 - C2 - C1
对于A3:M = A3 - x3 + x4 --> x4 - x3 = M - A3 = -C3 --> x4 = x1 - C3 - C2 - C1
所以:被转手的金币总数即每个人收到的金币的总和,即x1 + x2 + ..... + xn 
			则对于上图:ans = |x1| + |x2| + |x3| + |x4|
										= |x1| + |x1 - C1| + |x1 - C1 - C2| + |x1 - C1 - C2 - C3|
因此要想结果最小,则x1应该取C1 、C2 ......Cn的中位数

综上:只需要计算出x1的值再按照上面推导出来的式子计算出来即可

代码如下:

#include <iostream>
#include <vector>
#include <algorithm>

typedef long long LL ;
using namespace std ;

int main(){
    int n ;
    while (scanf("%d" , &n) == 1){
        vector<LL> gold(1 , 0) ;
        LL x , ans = 0 ;
        for(int i = 0 ; i < n ; ++ i){
            scanf("%lld" , &x) ;
            gold.push_back(x + gold.back()) ;       //存储前缀和
        }
        x = gold.back() / n ;       //将平均数(即最终每个人拥有的金币数)赋值给 x
        for(int i = 1 ; i <=n ; ++ i)
            gold[i] -= x * i ;      //计算C1 + ..... + Ci
        gold.erase(gold.begin() + 0) ;      //删除掉头部方便计算前缀和的无效数据 0
        sort(gold.begin() , gold.end()) ;       //排序
        x = gold[(gold.size() + 1) / 2] ;       //找到中位数
        for(auto i : gold)
            ans += abs(x - i) ;         //计算|x1 - C1 - ...... - Cn|
        printf("%lld\n" , ans) ;
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/just_gong/article/details/107835541
今日推荐