• Uva 11300 Spreading the Wealth(贪心)


    题目链接:https://vjudge.net/problem/UVA-11300

    这道题的思路太神了,但很难想到是贪心。

    用M表示每个人最终拥有的金币数。

    首先假设有四个人。假设1号给2号3枚,2号又给1号5枚,那么实际上1号并没有给2号,而2号给了1号2枚。这样设$x_2$表示2号给了1号$x_2$枚。若$x_2<0$,那么就表示1号给了2号$-x_2$枚。这样我们就相当于在1号和2号之间连了一条边,表示1号2号之间硬币关系(注意是环形,所以$x_1$表示1号和4号之间的硬币关系)。

    假设1号原来有$A_1$枚硬币,那么根据1号给了4号$x_1$枚,收到了$x_2$枚硬币,所以现在1号手中有$A_1+x_2-x_1$枚。根据开始的M,我们可以得到:$M=A_1+x_2-x_1$。同理,我们可以得到其他的方程。

    得到n-1个方程之后,可以尝试用$x_1$表示其他的$x_i$:

    对于第1个人:$M=A_1+x_2-x_1$ --> $x_2=M-A_1+x_1=x_1-C_1$(规定$C_1=A_1-M_1$);

    对于第2个人:$M=A_2+x_3-x_2$ --> $x_3=M-A_2+x_2=M-A_2+(M-A_1+x_1)=2 imes M-A_1-A_2+x_1=x_1-C_2$

    .....

    然而对于第n个人,这个式子是多余的——关于n的两个x,已在n-1和1中计算了。

    现在我们希望所有$x_i$的绝对值要尽可能地小,即$|x_1|+|x_1-C_1|+cdots +|x_1-C_{n-1}|$的最小,而它的几何意义便是在数轴上找一个点使得这个点到所有C的距离最短。我们会发现这个点便是这些数的中位数(奇偶都是)。

    注意一些边界问题..

    (详细证明见 蓝书P5)

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 
     7 using namespace std;
     8 
     9 const int maxn=1000005;
    10 
    11 int n;
    12 long long mid,ans,sum,M;
    13 long long A[maxn],C[maxn];
    14 
    15 inline void init(){
    16     memset(A,0,sizeof(A));
    17     sum=ans=0;
    18 }
    19 
    20 int main(){
    21     while(scanf("%d",&n)!=EOF){
    22         init();
    23         for(int i=1;i<=n;i++){
    24             scanf("%lld",&A[i]);
    25             sum+=A[i];
    26         }
    27         M=sum/n;
    28         for(int i=1;i<n;i++) C[i]=C[i-1]+A[i]-M;
    29         sort(C,C+n);
    30         mid=C[n/2];
    31         for(int i=0;i<n;i++) ans+=abs(C[i]-mid);
    32         printf("%lld
    ",ans);
    33     }
    34     return 0;
    35 } 
    AC代码
  • 相关阅读:
    Jquery开发技巧汇总
    (转)
    C#中的委托和时间
    asp.net中like 使用参数化(转)
    省市选择
    安卓对话框
    z转自 西西吹雪
    winform控件验证技术(转)
    C#获取网卡Mac地址 .(转)
    关于GDI+错误的修正
  • 原文地址:https://www.cnblogs.com/New-ljx/p/12230930.html
Copyright © 2020-2023  润新知