[2019牛客网多校训练第1场]Euclidean Distance

链接:https://ac.nowcoder.com/acm/contest/881/C
来源:牛客网

Bobo has a point A in the n n n dimension real space R n R_n Rn, whose coodinate is ( a 1 / m , a 2 / m , … , a n / m ) (a_1/m,a_2/m,…,a_n/m) (a1/m,a2/m,,an/m) where a i a_i ai and m are both integers. He wants to find another point P = ( p 1 , p 2 , … , p n ) P=(p_1,p_2,…,p_n) P=(p1,p2,,pn) meeting the following requirements.

  • p 1 , p 2 , … , p n ∈ R p_1,p_2,…,p_n∈R p1,p2,,pnR. That is, they are real numbers.
  • p 1 , p 2 , … , p n ≥ 0 p_1,p_2,…,p_n≥0 p1,p2,,pn0
  • p 1 + p 2 + ⋯ + p n = 1 p_1+p_2+⋯+p_n=1 p1+p2++pn=1
  • The (squared) Euclidean distance between P P P and A A A, which is ∥ A − P ∥ 2 = ∑ n i = ∑ ( a i / m − p i ) 2 ∥A−P∥^2=∑n_i=\sum(a_i/m−p_i)^2 AP2=ni=(ai/mpi)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 n n integers a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an.

  • 1 ≤ n ≤ 1 0 4 1≤n≤10^4 1n104
  • 1 ≤ m ≤ 1 0 3 1≤m≤10^3 1m103
  • − m ≤ a i ≤ m −m≤a_i≤m maim
  • The sum of n n n does not exceed 5 × 1 0 5 5×10^5 5×105.

输出描述:
For each test case, print a fraction which denotes the result.

输入

1 1
0
2 3
1 2
3 10
1 -2 3

输出

1
0
16/75

题意:
给定 n n n个数字 a 1 a_1 a1 a n a_n an,要求 n n n个实数 p 1 p_1 p1 p n p_n pn,使得 ∑ ( a i / m − p i ) 2 \sum(a_i/m−p_i)^2 (ai/mpi)2最小
并且满足:
p 1 , p 2 , … , p n ≥ 0 p_1,p_2,…,p_n≥0 p1,p2,,pn0
p 1 + p 2 + ⋯ + p n = 1 p_1+p_2+⋯+p_n=1 p1+p2++pn=1

输出最小的答案,用最简分数表示。

题解:
由于 a i a_i ai互相之间不会影响,所以顺序可以打乱。
a i a_i ai从大到小排序,枚举将最大的 i i i a i a_i ai处理成同一个值,我们把前i个 a i a_i ai处理成同一个值的时候,假设代价为每个数字和它的初始值的绝对值之差,消耗的代价总和不能超过 m m m。当不能继续放置的时候(设总代价为k),我们就可以将剩余的 m − k m-k mk的代价均摊到所有非负的 a i a_i ai值上,然后他们对答案分子的贡献就是 ( m − k − s t ∗ v ) 2 (m-k-st*v)^2 (mkstv)2(st为处理成同一个值的 a i a_i ai个数, v v v s t st st a i a_i ai处理成的同一个值),剩余的每个 a i a_i ai对答案分子的贡献就是 s t ∗ a [ i ] ∗ a [ i ] st*a[i]*a[i] sta[i]a[i],分母的值为 s t ∗ m ∗ m st*m*m stmm

补充一下贪心的正确性证明:
1.
g > p / c g>p/c g>p/c时,同样的值 p p p,如果均摊到 c c c个一样的数字 g g g上所得到的答案值为 c ∗ ( g − p / c ) 2 = g 2 ∗ c + p 2 / c − 2 ∗ g ∗ p c*(g-p/c)^2=g^2*c+p^2/c-2*g*p c(gp/c)2=g2c+p2/c2gp,如果这个值 p p p全都减到一个 g g g上了话,所得到的答案值会是 ( g − p ) 2 + ( c − 1 ) ∗ g 2 = p 2 + g 2 ∗ c (g-p)^2+(c-1)*g^2 = p^2+g^2*c (gp)2+(c1)g2=p2+g2c 由于现在讨论的 g , p , c g,p,c g,p,c均为非负整数,所以 p 2 + g 2 ∗ c > = g 2 ∗ c + p 2 / c − 2 ∗ g ∗ p p^2+g^2*c >= g^2*c+p^2/c-2*g*p p2+g2c>=g2c+p2/c2gp
这个是为什么最后分不完的话要均分成 i i i份的理由
2.
我们知道一件事情,对于一个两个正数 a a a, b b b,还有一个数字 p ( 0 < = p < a , b ) p(0<=p<a,b) p(0<=p<a,b) 如果 a > b a>b a>b那么根据完全平方公式 a 2 − ( a − p ) 2 = 2 ∗ a ∗ p > b 2 − ( b − p ) 2 = 2 ∗ b ∗ p a^2-(a-p)^2=2*a*p > b^2-(b-p)^2=2*b*p a2(ap)2=2ap>b2(bp)2=2bp那么意思就是说这个 p p p如果是被大的数字减去的话,能够将答案减少的量更多,所以我们将这个数字让大的减去。
这个是不断将大的数字变为相同的更小的数字的理由。
3.
我们知道,如果 a i a_i ai是小于0的话,那么它对应的 p i p_i pi如果越大,他对答案的负贡献越大,所以如果 a i a_i ai是小于 0 0 0的话,它对应的 p i p_i pi一律为 0 0 0。除非后面有剩余的 m m m需要分配,才会为了使得所有数字都尽量不要太小才平均分配给每一个数字,那么这时候对于负数的操作就跟正数完全相同了。

#include
#define ll long long
#define pa pair
using namespace std;
ll a[10004];
ll ans,m;
int n;
int w33ha(){
    ans=0;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1,greater<int>());
    ll nd=0;
    for(int i=1;i<=n;i++){
        if(i<n&&(a[i]-a[i+1])*i+nd<=m){
            nd+=(a[i]-a[i+1])*i;
        }
        else{
            ans=(m-nd-i*a[i])*(m-nd-i*a[i]);
            for(int j=i+1;j<=n;j++){
                ans+=i*a[j]*a[j];
            }
            ll d,p=i*m*m;
            if(ans==0)return puts("0");
            d=__gcd(ans,p);
            ans/=d;p/=d;
            if(p==1)printf("%lld\n",ans);
            else printf("%lld/%lld\n",ans,p);
            return 0;
        }
    }
    return 0;
}
int main(){
    while(scanf("%d%lld",&n,&m)!=EOF)w33ha();
    return 0;
}

你可能感兴趣的:([2019牛客网多校训练第1场]Euclidean Distance)