zoukankan      html  css  js  c++  java
  • UVA

    UVA - 11300 Spreading the Wealth

    【题目描述】

    圆桌旁边坐着n个人,每个人有一定数量的金币,金币的总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数量相等。您的任务是求出被转手的金币的数量的最小值。

    【输入格式】

    输入包含多组数据。每组数据第一行为一个整数n(n<=1000000)0),以下n行每行为一个整数,按逆时针顺序给出每个人拥有的金币数。输入结束标志为文件结束符(EOF)

    【输出格式】

    对于每组数据,输出被转手的金币的数量的最小值。输入保证这个值在 64位无符号整数的范围之内。

    【Sample】

    Input

    3
    100
    100
    100
    4
    1
    2
    5
    4
    

    Output

    0
    4
    

    【Solution】

    这是一道数学题
    根据题意
    每个人都可以给两边人传递硬币
    为了简化问题
    我们定向每个人i只能给下一个人x[i]枚硬币
    那么我们的答案就是求(|x_1| + |x_2| + ... + |x_n|)的最小值
    假设最终每个人分到num枚硬币
    那么当前第i个人的情况是
    a[i] - x[i] + x[i + 1] = num;
    接下来就是推导式子

    (x_{i+1} = num - a_i + x_i)

    (x_2 = num - a_1 + x_1)
    (x_3 = num - a_2 + x_2)
    联立上述两个式子得到
    (x_2 = x_1 - (a_1 - num));
    (x_3 = x_2 - (a_1 + a_2 - 2 * num))
    同理我们可以写出(1) ~ (n)所有的项数
    所有的式子相加可以得到
    $x_i = x_1 - $ (sum_{i = 1}^{n - 1} a_j - (n - 1) * m)
    由此可见,我们要求得答案只与(x_1)有关
    拿一个(tmp_i)表示后面的一大坨(sum_{i = 1}^{n - 1} a_j - (n - 1) * m)
    我们的答案的表达式为
    (|x_1| + |x_2| + ... + |x_n| = |x_1| + |x_1 - tmp_2| + |x_1- tmp_3| + ... + |x_1- tmp_n|)
    根据这是一道数学题
    不难想到
    上述等式右边表示(x _ 1)(tmp_1)~(tmp_n)的距离之和
    显然,当(x_1)为集合$ {tmp_n} $的中位数时
    该式子取得最小值

    代码

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    inline int read(){
        int x = 0, w = 1;
        char ch = getchar();
        for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
        return x * w;
    }
    
    const int maxn = 1000010;
    int a[maxn], tmp[maxn];
    int num, n;
    
    signed main(){
        while(scanf("%lld", &n) != EOF){
            memset(a, 0, sizeof a);
            memset(tmp, 0, sizeof tmp);
            int ans = 0;
            int sum = 0;
            for(int i = 1; i <= n ;i++){
                a[i] = read();
                sum += a[i];
            }
            num = sum / n;
            tmp[1] = 0;
            for(int i = 1; i < n; i++){
                tmp[i + 1] = num - a[i] + tmp[i];
            }
            sort(tmp + 1, tmp + 1 + n);
            int x = tmp[n / 2];
            for(int i = 1; i <= n; i++){
                ans += abs(x - tmp[i]);
            }
            cout << ans << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    ftp上传下载
    java生成xml
    Java:删除某文件夹下的所有文件
    java读取某个文件夹下的所有文件
    JFileChooser 中文API
    得到java异常printStackTrace的详细信息
    关于SQL命令中不等号(!=,<>)
    ABP前端保存notify提示在Edge浏览器显示null
    关于MY Sql 查询锁表信息和解锁表
    VS2019 backspace键失效,无法使用
  • 原文地址:https://www.cnblogs.com/rui-4825/p/12660086.html
Copyright © 2011-2022 走看看