“放弃不难,但坚持一定很酷。”
QQ 小方已经在体育馆苦练一天射箭了,但他还在坚持。
QQ 小方每天都要在朋友圈晒自己的训练记录。他一共进行了 n 次射箭,成绩分别是 x1,x2,⋯,xn。为了表现自己的发挥十分稳定,QQ 小方决定选出其中的 m 次成绩,使得他们的方差是所有可以选择的方案中最小的。
对于 m 个元素组成的数列 a1,a2,⋯,am,我们知道他们的方差 σ2=(a1−a¯)2+(a2−a¯)2+⋯+(am−a¯)2m ,其中 a¯=a1+a2+⋯+amm。
但是这个问题对 QQ 小方来说太难了,你需要去帮助 QQ 小方。
为了方便,现在你需要输出这个最小的 σ2 乘以 m2 以后的结果。
输入
输入一行包含两个正整数 n (1≤n≤106) 和 m (1≤m≤n)。接下来一行包含 n 个整数 x1,x2,⋯,xn (1≤xi≤103)。
输出
输出一行包含一个整数,表示答案。为了方便,我们需要输出最小的 σ2 乘以 m2 以后的结果。
样例
input
5 3 1 2 3 4 5
output
6
这题一看就得转化、
我们有这样一个公式,即
D(x) = E(x^2) - E(x)^2(D(x)表示x的方差,E(x)表示期望,也就是平均值)
要选m个,首先你得sort一下吧,取得m个肯定是sort之后连续的m个,仔细想一下为什么
然后我们就可以预处理一个x和x^2前缀和
然后枚举区间就完了
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn = 1e6+7;
int n,m;
ll Sum2[maxn],Sum[maxn],a[maxn];
ll o2(ll x){
return x*x;
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1,x;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
Sum2[i] = Sum2[i-1]+a[i]*a[i];
Sum[i] = Sum[i-1]+a[i];
}
ll ans = 1e18;
for(int i=m;i<=n;i++){
ll E2m = (Sum2[i] - Sum2[i-m])*m;
ll Em2 = o2(Sum[i] - Sum[i-m]);
ans = min(ans,E2m - Em2);
}
printf("%lld\n",ans);
return 0;
}