题目链接

传送门

题意

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

  • \(p_i\in\mathbb{R}\);
  • \(p_i\geq 0,i\in[1,n]\);
  • \(\sum\limits_{i=1}^{n}p_i=m\)。

思路

由于叉姐的题解太高深了,本菜鸡完全看不懂(爆哭),因此我们从其他角度来求解本题。

首先根据题目要求的式子和条件可以发现我们能做的只是将\(p_i\)合理赋值使得\(\sum\limits_{i=1}^{n}(a_i-p_i)^2\)最小,且\(a_i\in[-m,m],p_i\in[0,m]\),那么\(p_i\)只能将\(a_i\)的值不断减小而不能增加(即使\(a_i<0\)),因此我们就可以通过调节\(p_i\)的值使得\(a_i\)的最大值尽可能的小,且\(\sum\limits_{i=1}^{n}p_i=m\)。

假设我们进行处理前\(i-1\)后\(p\)的和还剩下\(las\),前\(i\)个的\(a\)的值都已经被削到了\(a_i\),那么:

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

其中的\(idx\)就是说我们可以通过调节\(p_i\)的值使得前\(idx\)个数都相等且等于\(a_{idx}-\frac{las}{idx}\),因此最后答案是\(\frac{idx\times(a_{idx}-\frac{las}{idx})^2+\sum\limits_{i=idx+1}^{n}a_{idx}^2}{m^2}\)(因为我们最初始时将\(a_i,p_i\)都扩大了\(m\)倍,将\(m\)丢到了分母)。

如果没看懂我们可以通过分析样例\(3\)来帮助理解:

首先我们将\(a\)数组排序得到:

    \(3\)     \(1\)     \(-2\)

  • 处理前\(1\)个数,此时\(las=10>1\times|1-3|=2\),于是我们将\(a_1\)变成\(1\),\(las\)消耗\(2\);
  • 处理前\(2\)个数,此时\(las=8>2\times|-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\times 3}{10\times 10}=\frac{16}{75}\)。

\(update\):

证明这个写法的正确性:

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

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

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

\[\begin{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,m\geq 0\)时均分最优:

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

\[\begin{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)(\text{题目给定的}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("*********\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;
}

2019年牛客多校第一场 C题Euclidean Distance 暴力+数学的更多相关文章

  1. 2019年牛客多校第一场B题Integration 数学

    2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...

  2. 2019年牛客多校第一场 I题Points Division 线段树+DP

    题目链接 传送门 题意 给你\(n\)个点,每个点的坐标为\((x_i,y_i)\),有两个权值\(a_i,b_i\). 现在要你将它分成\(\mathbb{A},\mathbb{B}\)两部分,使得 ...

  3. 2019年牛客多校第一场 H题XOR 线性基

    题目链接 传送门 题意 求\(n\)个数中子集内所有数异或为\(0\)的子集大小之和. 思路 对于子集大小我们不好维护,因此我们可以转换思路变成求每个数的贡献. 首先我们将所有数的线性基的基底\(b\ ...

  4. 2019年牛客多校第一场 B题 Integration 数学

    题目链接 传送门 思路 首先我们对\(\int_{0}^{\infty}\frac{1}{\prod\limits_{i=1}^{n}(a_i^2+x^2)}dx\)进行裂项相消: \[ \begin ...

  5. 2019年牛客多校第一场 E题 ABBA DP

    题目链接 传送门 思路 首先我们知道\('A'\)在放了\(n\)个位置里面是没有约束的,\('B'\)在放了\(m\)个位置里面也是没有约束的,其他情况见下面情况讨论. \(dp[i][j]\)表示 ...

  6. Cutting Bamboos(2019年牛客多校第九场H题+二分+主席树)

    题目链接 传送门 题意 有\(n\)棵竹子,然后有\(q\)次操作,每次操作给你\(l,r,x,y\),表示对\([l,r]\)区间的竹子砍\(y\)次,每次砍伐的长度和相等(自己定砍伐的高度\(le ...

  7. 2019年牛客多校第二场 F题Partition problem 爆搜

    题目链接 传送门 题意 总共有\(2n\)个人,任意两个人之间会有一个竞争值\(w_{ij}\),现在要你将其平分成两堆,使得\(\sum\limits_{i=1,i\in\mathbb{A}}^{n ...

  8. MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)

    题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...

  9. Kth Minimum Clique(2019年牛客多校第二场D题+k小团+bitset)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 找第\(k\)小团. 思路 用\(bitset\)来标记每个结点与哪些结点直接有边,然后进行\(bfs\),在判断新加入的点与现在有的点是否都 ...

随机推荐

  1. [LeetCode] 901. Online Stock Span 线上股票跨度

    Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of ...

  2. PHP下载远程图片到本地的几种方法总结(tp5.1)

    1.CURL 2.使用file_get_contents 3.使用fopen 参考链接:https://www.jb51.net/article/110615.htm

  3. 如何修改通过Anaconda安装的jupyter notebook的工作目录

    通过Anaconda安装jupyter notebook,对新手来说是一个非常明智的选择,可以避免很多不必要的麻烦! jupyter notbook默认情况下的工作目录是c:\user\...,接下来 ...

  4. Tkint中Label&Button&Scale的使用

    top.geometry()设定窗口的初始大小 scale.set()设定滑块的初始值 scale.get()获取滑块变化的值 控件通过回调函数与其他控件进行通信(Label控件中的文本会受到Scal ...

  5. PHP 使用 pdo 操作oracle数据库 报错

    ## SELECT UNID,NAME,NAME_XML WHERE UNID>=10 AND UNID<=15 ## 在10到15这5条数据中不为空数据php: symbol looku ...

  6. docker redis4.0集群搭建

    一.前言 redis集群对于很多人来说非常熟悉,在前些日子,我也有一位大兄弟也发布过一篇关于在阿里云(centOS7)上搭建redis 集群的文章,虽然集群搭建的文章在网上很多,我比较喜欢这篇文章的地 ...

  7. Oracle学习笔记(四)

    Oracle中的体系结构: oracle体系结构中的进程: 共享池相关的优化: drop table t purge; create table t as select * from dba_obje ...

  8. 简单计算器设计(WPF)

    要求: 文本框居中,用户不能修改运算结果 当用户选择不同的运算类型时 下方GroupBox的标题与所选运算类型相对应 且文本框数字立即清空 单击[计算]按钮时 如果文本框输入的内容非法 结果文本框显示 ...

  9. C# 利用MS的 EntLib的Database类编写的DbHelper

    C# 利用MS的 EntLib的Database类编写的DbHelper,由于MS的EntLib对Oracle.SQL Server和MySql已经封装,所以可以该DbHelper可以适用这三种数据库 ...

  10. 2019 超级老板APPjava面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.超级老板等公司offer,岗位是Java后端开发,因为发展原因最终选择去了超级老板,入职一年时间了,也成为了面 ...