• 【bzoj1465/bzoj1045】糖果传递 数论


    题目描述

    老师准备了一堆糖果, 恰好n个小朋友可以分到数目一样多的糖果. 老师要n个小朋友去拿糖果, 然后围着圆桌坐好, 第1个小朋友的左边是第n个小朋友, 其他第i个小朋友左边是第i-1个小朋友. 大家坐好后, 老师发现, 有些小朋友抢了很多的糖果, 有的小朋友只得到了一点点糖果, 甚至一颗也没有 , 设第i个小朋友有ai颗糖果. 小朋友们可以选择将一些糖果给他左边的或者右边的小朋友, 通过”糖果传递”最后使得每个小朋友得到的糖果数是一样多的, 假设一颗糖果从一个小朋友传给另一个小朋友的代价是1, 问怎样传递使得所耗的总代价最小.

    输入

    第一行一个正整数n,表示小朋友的个数. n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

    输出

    输出只有一个数, 表示最小代价.

    样例输入

    4
    1
    2
    5
    4

    样例输出

    4


    题解

    数论?! Orz http://hzwer.com/2656.html

    设第i个小朋友给第i-1个小朋友的糖果数为xi(第1个给第n个),

    由于每个小朋友最后剩余的糖果数都是平均数ave,那么有:

    a1-x1+x2=ave

    a2-x2+x3=ave

    ……

    an-xn+x1=ave

    可以看出最后一个方程可以由前n-1个推出来,是多余的,于是怒删

    将这里的前i个方程加起来,可以发现其中的变量只包含xi+1和x1,即xi+1=ave*i-∑aj (1≤j≤i),即xi=ave*(i-1)-∑aj (1≤j<i)

    为了方便,令ci=∑(aj-ave) (1≤j≤i),就变成了xi=x1-c(i-1)。

    所求为|x1|+|x2|+……+|xn|=|x1-0|+|x1-c1|+|x1-c2|+...+|x1-c(i-1)|

    根据某定理,x1等于0、c1、c2、...、c(i-1)的中位数时所求最小。

    然后加一遍就行了。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    ll a[1000010] , c[1000010];
    int main()
    {
    	int n , i;
    	ll ave = 0 , ans = 0;
    	scanf("%d" , &n);
    	for(i = 1 ; i <= n ; i ++ )
    		scanf("%lld" , &a[i]) , ave += a[i];
    	ave /= n;
    	for(i = 2 ; i <= n ; i ++ )
    		c[i] = c[i - 1] + a[i] - ave;
    	sort(c + 1 , c + n + 1);
    	for(i = 1 ; i <= n ; i ++ )
    		ans += abs(c[i] - c[(n + 1) >> 1]);
    	printf("%lld
    " , ans);
    	return 0;
    }

     

  • 相关阅读:
    九、分布式事务
    L2008 最长对称子串
    L2004 这是二叉搜索树吗?
    L2001 紧急救援
    L2003 月饼
    L2007 家庭房产
    L2006 树的遍历
    L2009 抢红包
    L2005 集合相似度
    L2002 链表去重
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6550081.html
Copyright © 2020-2023  润新知