• 2019年牛客多校第一场 C题Euclidean Distance 暴力+数学


    题目链接

    传送门

    题意

    给你(n)个数(a_i),要你在满足下面条件下使得(sumlimits_{i=1}^{n}(a_i-p_i)^2)最小(题目给的(m)只是为了将(a_i)变成一个整数,那么我们就当此处的(p_i)扩大为题目给的(m)倍,然后把(m)放到分母去,以下不再解释):

    • (p_iinmathbb{R})
    • (p_igeq 0,iin[1,n])
    • (sumlimits_{i=1}^{n}p_i=m)

    思路

    由于叉姐的题解太高深了,本菜鸡完全看不懂(爆哭),因此我们从其他角度来求解本题。
    首先根据题目要求的式子和条件可以发现我们能做的只是将(p_i)合理赋值使得(sumlimits_{i=1}^{n}(a_i-p_i)^2)最小,且(a_iin[-m,m],p_iin[0,m]),那么(p_i)只能将(a_i)的值不断减小而不能增加(即使(a_i<0)),因此我们就可以通过调节(p_i)的值使得(a_i)的最大值尽可能的小,且(sumlimits_{i=1}^{n}p_i=m)
    假设我们进行处理前(i-1)(p)的和还剩下(las),前(i)个的(a)的值都已经被削到了(a_i),那么:

    • 如果(i imes|(a[i+1]-a[i])|leq las),那么(las=las-i imes|(a[i+1]-a[i])|)
    • 否则,就记录这个位置为(idx),并且(break)(idx)的初始值为(n))。

    其中的(idx)就是说我们可以通过调节(p_i)的值使得前(idx)个数都相等且等于(a_{idx}-frac{las}{idx}),因此最后答案是(frac{idx imes(a_{idx}-frac{las}{idx})^2+sumlimits_{i=idx+1}^{n}a_{idx}^2}{m^2})(因为我们最初始时将(a_i,p_i)都扩大了(m)倍,将(m)丢到了分母)。
    如果没看懂我们可以通过分析样例(3)来帮助理解:
    首先我们将(a)数组排序得到:
        (3)     (1)     (-2)

    • 处理前(1)个数,此时(las=10>1 imes|1-3|=2),于是我们将(a_1)变成(1)(las)消耗(2)
    • 处理前(2)个数,此时(las=8>2 imes|-2-1|=6),于是我们将(a_1,a_2)变成(-2)(las)消耗(6)
    • 处理前(3)个数,此时(las=2,a_1=a_2=a_3=-2),由于(las)最后要变成(0)(a_i)的最大值要尽可能小,那么我们需要均匀分配,所以最后(a_1=a_2=a_3=-2-frac{2}{3}=-frac{8}{3})

    所以最后答案为(frac{(-frac{8}{3})^2 imes 3}{10 imes 10}=frac{16}{75})
    (update)

    证明这个写法的正确性:

    假设现在有两个数(a,b(ageq b)),总的可以减少的数量为(m)

    1.首先证明当(a-bgeq m)时全放在(a)上最优:

    (m)中有(x(1leq xleq m))用在(b)上,那么和为((a-m+x)^2+(b-x)^2),全用在(a)上的话和为((a-m)^2+b^2),两者做差:

    [egin{aligned} &(a-m+x)^2+(b-x)^2-(a-m)^2-b^2&\ =&(a-m)^2+2x(a-m)+x^2+b^2-2bx+x^2-(a-m)^2-b^2&\ =&2x^2+2x(a-m)-2bx&\ =&2x^2+2x(a-b-m)geq 0& end{aligned} ]

    2.再证明当(a=b,mgeq 0)时均分最优:

    (m)中有(x(1leq x< frac{m}{2}))用在(b)上,那么和为((a-m+x)^2+(b-x)^2),将其化简:

    [egin{aligned} &(a-m+x)^2+(b-x)^2&\ =&(a-m)^2+2(a-m)x+x^2+b^2-2bx+x^2&\ =&(a-m)^2+b^2+2x^2+2(a-m-b)x&\ =&(a-m)^2+b^2+2(x^2-mx)( ext{题目给定的}a=b)& end{aligned} ]

    由于前一半和(x)无关,而后一半(x^2-mx=(x-frac{m}{2})^2-frac{m^2}{4})(x=frac{m}{2})时取最小值。

    最后我们来讨论有(n)个数分配(m),其中(a,b)分别为(n)个数中的最大和次大值时为什么当(m>a-b)时每次将最大值减小到次大值是最优的的情况:

    • ((1).)首先如果将(m)全部减到一个数上,那么肯定是减小最大值是最优的:((a-m)^2+c^2-a^2-(c-m)^2=a^2-2am+m^2+c^2-a^2-c^2+2cm-m^2=2m(c-a)<0(c)为剩余(n-1)个数中的任意一个数);
    • ((2).)如果分配到两个数上那么也一定时分到最大值和次大值上,理由同上;那么此时我们应该怎么分配最优呢?我们发现当(a)减少到(a=b)之后如果再减少(a)的话,(b)就已经大于(a)成为新的最大值了,那么再减小(a)肯定不是最优解(理由为((1))),因此只能将最大值(a)减小到次大值(b),然后根据上面的(2)得知均匀分配最优;
    • 分配到任意多个数的情况基本和((2))相同。

    因此我们可以得知本题的解决策略是正确的。
    (如果想法或者证明过程有错误,还请各位大佬指正~)

    代码实现如下

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> pLL;
    typedef pair<LL, int> pLi;
    typedef pair<int, LL> pil;;
    typedef pair<int, int> pii;
    typedef unsigned long long uLL;
    
    #define lson rt<<1
    #define rson rt<<1|1
    #define lowbit(x) x&(-x)
    #define name2str(name) (#name)
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("D://Code//in.txt","r",stdin)
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    
    const double eps = 1e-8;
    const int mod = 1000000007;
    const int maxn = 1e5 + 7;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    
    int n, m;
    int a[maxn];
    
    int main() {
    #ifndef ONLINE_JUDGE
    FIN;
    #endif // ONLINE_JUDGE
        while(~scanf("%d%d", &n, &m)) {
            for(int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
            }
            sort(a + 1, a + n + 1, [](int a, int b){return a > b;});
            int idx = n;
            int las = m;
            for(int i = 1; i < n; ++i) {
                if(i * abs(a[i+1] - a[i]) > las) {
                    idx = i;
                    break;
                } else {
                    las -= i * abs(a[i+1] - a[i]);
                }
            }
            LL num1 = 1LL * (idx * a[idx] - las) * (idx * a[idx] - las);
            LL num2 = 1LL * idx * m * m;
            for(int i = idx + 1; i <= n; ++i) {
                num1 += 1LL * a[i] * a[i] * idx;
            }
            LL tmp = __gcd(num1, num2);
            num1 /= tmp, num2 /= tmp;
            if(num2 == 1) printf("%lld
    ", num1);
            else printf("%lld/%lld
    ", num1, num2);
        }
        return 0;
    }
    
    
  • 相关阅读:
    android基础开发之scrollview
    java网络---再论URL & URI
    Android Studio 有用的插件
    java网络---查找Internet
    java网络---流
    Qt学习之路(1)------Qt常用类用法说明
    将批量下载的博客导入到手机后,通过豆约翰博客阅读器APP(Android手机)进行浏览,白字黑底,保护眼睛,图文并茂。
    如何收藏互联网上的任意网页到系统某个分类下,之后进行批量导出发布等---博客备份专家的博文收藏功能您不可不知
    很喜欢看某方面的文章,如何将不同站点,不同博主同一类别的文章归类整合到一起,再批量导出成各种格式---豆约翰博客备份专家新增按分类收藏博文功能
    豆约翰博客备份专家博客导出示例(PDF,CHM)
  • 原文地址:https://www.cnblogs.com/Dillonh/p/11215846.html
Copyright © 2020-2023  润新知