Bobo has a point A in the n dimension real space RnRn, whose coodinate is (a1/m,a2/m,…,an/m)(a1/m,a2/m,…,an/m) where aiai and m are both integers. He wants to find another point P=(p1,p2,…,pn)P=(p1,p2,…,pn) meeting the following requirements.
* p1,p2,…,pn∈Rp1,p2,…,pn∈R. That is, they are real numbers.
* p1,p2,…,pn≥0p1,p2,…,pn≥0
* p1+p2+⋯+pn=1p1+p2+⋯+pn=1
* The (squared) Euclidean distance between P and A, which is ∥A−P∥22=∑ni=1(ai/m−pi)2‖A−P‖22=∑i=1n(ai/m−pi)2, is minimized.
It can be proved the minimum is always a rational number. Print the squared distance in fraction. Note to print an integer n as `n` instead of `n/1`.
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains two integers n and m.
The second line contains n integers a1,a2,…,ana1,a2,…,an.
* 1≤n≤1041≤n≤104
* 1≤m≤1031≤m≤103
* −m≤ai≤m−m≤ai≤m
* The sum of n does not exceed 5×1055×105.
输出描述:
For each test case, print a fraction which denotes the result.
示例1
输入
复制
1 1
0
2 3
1 2
3 10
1 -2 3
输出
复制
1
0
16/75
传送门
题意:给定n个数字a1到an,要求n个实数p1到pn,使得最小
并且满足:
p1,p2,…,pn≥0
p1+p2+⋯+pn=1
输出最小的答案,用最简分数表示。
思路:首先进行通分 变成 那么此处的
扩大为题目给的m倍,要想分子最小,那么
只能将
的值不断减小而不能增加(即使ai<0),因此我们就可以通过调节
的值使得
的最大值尽可能的小),因此我们就可以通过调节
的值使得
的最大值尽可能的小,我们就m*
看成一个整体 那么总共减少值(ans)为m。
假设我们进行处理前i-1后的和还剩下ans,前i个的a的值都已经被削到了
,那么:
- 如果 i*(a[i]-a[i-1])<=ans,那么ans=ans-i*(a[i]-a[i-1]);// 下证 a数组从大到小排序
- 否则,就记录这个位置为indx,并且break(indx的初始值为n)。
其中的idnx就是说我们可以通过调节pi的值使得前idnx个数都相等且等于,因此最后答案是
举个例子
首先我们将aa数组排序得到:
3 1 −2
- 处理前1个数,此时ans=10>1*(3-1)=2,于是我们将a1变成1,ans消耗2;
- 处理前2个数,此时ans=8>2*(1-(-2))=6,于是我们将a1,a2变成-2,ans消耗6;
- 处理前3个数,此时ans=2,a1=a2=a3=-2,由于ans最后要变成0且ai的最大值要竟可能小,那么我们均匀分配,所以
。
所以最后答案为
证明
在此感谢大佬 https://blog.nowcoder.net/n/77aaf4ba0b8f477ba2613da5a7dcd2be
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int cmp(int x,int y)
{
return x>y;
}
int main()
{
ll n,m;
while(cin>>n>>m)
{
ll a[10100];
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n,cmp);
ll ans=m;
ll indx=n;
for(int i=1;i<n;i++)
{
if(i*(a[i]-a[i+1])>=ans)
{
indx=i;
break;
}
else
ans-=i*(a[i]-a[i+1]);
}
ll sum=1ll*(indx*a[indx]-ans)*(indx*a[indx]-ans);
for(int i=indx+1;i<=n;i++)
{
sum+=1ll*a[i]*a[i]*indx;
}
ll x=m*m*indx;
ll tmp=__gcd(x,sum);
sum/=tmp,x/=tmp;
if(x==1)
{
cout<<sum<<endl;
}
else
cout<<sum<<"/"<<x<<endl;
}
return 0;
}