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

题目链接

传送门

题意

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

  • p i ∈ R p_i\in\mathbb{R} piR
  • p i ≥ 0 , i ∈ [ 1 , n ] p_i\geq 0,i\in[1,n] pi0,i[1,n]
  • ∑ i = 1 n p i = m \sum\limits_{i=1}^{n}p_i=m i=1npi=m

思路

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

  • 如果 i × ∣ ( a [ i + 1 ] − a [ i ] ) ∣ ≤ l a s i\times|(a[i+1]-a[i])|\leq las i×(a[i+1]a[i])las,那么 l a s = l a s − i × ∣ ( a [ i + 1 ] − a [ i ] ) ∣ las=las-i\times|(a[i+1]-a[i])| las=lasi×(a[i+1]a[i])
  • 否则,就记录这个位置为 i d x idx idx,并且 b r e a k break break i d x idx idx的初始值为 n n n)。

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

  • 处理前 1 1 1个数,此时 l a s = 10 &gt; 1 × ∣ 1 − 3 ∣ = 2 las=10&gt;1\times|1-3|=2 las=10>1×13=2,于是我们将 a 1 a_1 a1变成 1 1 1 l a s las las消耗 2 2 2
  • 处理前 2 2 2个数,此时 l a s = 8 &gt; 2 × ∣ − 2 − 1 ∣ = 6 las=8&gt;2\times|-2-1|=6 las=8>2×21=6,于是我们将 a 1 , a 2 a_1,a_2 a1,a2变成 − 2 -2 2 l a s las las消耗 6 6 6
  • 处理前 3 3 3个数,此时 l a s = 2 , a 1 = a 2 = a 3 = − 2 las=2,a_1=a_2=a_3=-2 las=2,a1=a2=a3=2,由于 l a s las las最后要变成 0 0 0 a i a_i ai的最大值要尽可能小,那么我们需要均匀分配,所以最后 a 1 = a 2 = a 3 = − 2 − 2 3 = − 8 3 a_1=a_2=a_3=-2-\frac{2}{3}=-\frac{8}{3} a1=a2=a3=232=38

所以最后答案为 ( − 8 3 ) 2 × 3 10 × 10 = 16 75 \frac{(-\frac{8}{3})^2\times 3}{10\times 10}=\frac{16}{75} 10×10(38)2×3=7516
u p d a t e update update

证明这个写法的正确性:

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

1.首先证明当 a − b ≥ m a-b\geq m abm时全放在 a a a上最优:

m m m中有 x ( 1 ≤ x ≤ m ) x(1\leq x\leq m) x(1xm)用在 b b b上,那么和为 ( a − m + x ) 2 + ( b − x ) 2 (a-m+x)^2+(b-x)^2 (am+x)2+(bx)2,全用在 a a a上的话和为 ( a − m ) 2 + b 2 (a-m)^2+b^2 (am)2+b2,两者做差:
( a − m + x ) 2 + ( b − x ) 2 − ( a − m ) 2 − b 2 = ( a − m ) 2 + 2 x ( a − m ) + x 2 + b 2 − 2 b x + x 2 − ( a − m ) 2 − b 2 = 2 x 2 + 2 x ( a − m ) − 2 b x = 2 x 2 + 2 x ( a − b − m ) ≥ 0 \begin{aligned} &amp;(a-m+x)^2+(b-x)^2-(a-m)^2-b^2&amp;\\ =&amp;(a-m)^2+2x(a-m)+x^2+b^2-2bx+x^2-(a-m)^2-b^2&amp;\\ =&amp;2x^2+2x(a-m)-2bx&amp;\\ =&amp;2x^2+2x(a-b-m)\geq 0&amp; \end{aligned} ===(am+x)2+(bx)2(am)2b2(am)2+2x(am)+x2+b22bx+x2(am)2b22x2+2x(am)2bx2x2+2x(abm)0

2.再证明当 a = b , m ≥ 0 a=b,m\geq 0 a=b,m0时均分最优:

m m m中有 x ( 1 ≤ x &lt; m 2 ) x(1\leq x&lt; \frac{m}{2}) x(1x<2m)用在 b b b上,那么和为 ( a − m + x ) 2 + ( b − x ) 2 (a-m+x)^2+(b-x)^2 (am+x)2+(bx)2,将其化简:
( a − m + x ) 2 + ( b − x ) 2 = ( a − m ) 2 + 2 ( a − m ) x + x 2 + b 2 − 2 b x + x 2 = ( a − m ) 2 + b 2 + 2 x 2 + 2 ( a − m − b ) x = ( a − m ) 2 + b 2 + 2 ( x 2 − m x ) ( 题目给定的 a = b ) \begin{aligned} &amp;(a-m+x)^2+(b-x)^2&amp;\\ =&amp;(a-m)^2+2(a-m)x+x^2+b^2-2bx+x^2&amp;\\ =&amp;(a-m)^2+b^2+2x^2+2(a-m-b)x&amp;\\ =&amp;(a-m)^2+b^2+2(x^2-mx)(\text{题目给定的}a=b)&amp; \end{aligned} ===(am+x)2+(bx)2(am)2+2(am)x+x2+b22bx+x2(am)2+b2+2x2+2(amb)x(am)2+b2+2(x2mx)(题目给定的a=b)
由于前一半和 x x x无关,而后一半 x 2 − m x = ( x − m 2 ) 2 − m 2 4 x^2-mx=(x-\frac{m}{2})^2-\frac{m^2}{4} x2mx=(x2m)24m2 x = m 2 x=\frac{m}{2} x=2m时取最小值。

最后我们来讨论有 n n n个数分配 m m m,其中 a , b a,b a,b分别为 n n n个数中的最大和次大值时为什么当 m &gt; a − b m&gt;a-b m>ab时每次将最大值减小到次大值是最优的的情况:
  • ( 1 ) . (1). (1).首先如果将 m m m全部减到一个数上,那么肯定是减小最大值是最优的: ( a − m ) 2 + c 2 − a 2 − ( c − m ) 2 = a 2 − 2 a m + m 2 + c 2 − a 2 − c 2 + 2 c m − m 2 = 2 m ( c − a ) &lt; 0 ( c (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)&lt;0(c (am)2+c2a2(cm)2=a22am+m2+c2a2c2+2cmm2=2m(ca)<0(c为剩余 n − 1 n-1 n1个数中的任意一个数);
  • ( 2 ) . (2). (2).如果分配到两个数上那么也一定时分到最大值和次大值上,理由同上;那么此时我们应该怎么分配最优呢?我们发现当 a a a减少到 a = b a=b a=b之后如果再减少 a a a的话, b b b就已经大于 a a a成为新的最大值了,那么再减小 a a a肯定不是最优解(理由为 ( 1 ) (1) (1)),因此只能将最大值 a a a减小到次大值 b b b,然后根据上面的 2 2 2得知均匀分配最优;
  • 分配到任意多个数的情况基本和 ( 2 ) (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("*********\n")
#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\n", num1);
        else printf("%lld/%lld\n", num1, num2);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值