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 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值