题干:
若x1,x2,x3……xn的平均数为k。 则方差s^2 = 1/n * [(x1-k)^2+(x2-k)^2+…….+(xn-k)^2] 。 方差即偏离平方的均值,称为标准差或均方差,方差描述波动程度。
给出M个数,从中找出N个数,使这N个数方差最小。
Input
第1行:2个数M,N,(M > N, M <= 10000)
第2 - M + 1行:M个数的具体值(0 <= Xi <= 10000)
Output
输出最小方差 * N的整数部分。
Input示例
5 3
1
2
3
4
5
Output示例
2
解题报告:
首先想到这题肯定是要排序的,方差就是稳定程度嘛,肯定相邻的两个数好过不相邻的两个数,然后我们进行公式化简:
文章图片
因为我们知道,数据范围是1e4,所以n^2的复杂度虽然也可以但是我们还有更优秀的nlogn的方法:排序用去了nlogn,所以其他的部分最好在o(n)内完成。而我们观察原公式后发现如果直接求的话,那每一次遍历都需要o(m)求一遍k,那就又成o(nm)复杂度了,和n^2是一个数量级的,肯定不行,所以我们考虑用
文章图片
这一条性质巧妙的把k约掉,发现得出的这两项刚好满足前缀和类性质,于是可以o(1)查询了,然后o(n-m)遍历一遍,就可以出答案了。
下面上代码:
#include
#define ll long long
using namespace std;
const int MAXN = 1e4+5;
ll a[MAXN], sum[MAXN], summ[MAXN];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;
i<=n;
i++) {
scanf("%lld",&a[i]);
}
sort(a+1, a+1+n);
sum[0] = summ[0] = 0;
for(int i=1;
i<=n;
i++) {
sum[i] = sum[i-1] + a[i];
summ[i] = summ[i-1] + a[i]*a[i];
}
double minn = (double)LLONG_MAX;
for(int i=m;
i<=n;
i++) {
double tmp = (summ[i]-summ[i-m])-1.0*(sum[i]-sum[i-m])*(sum[i]-sum[i-m])/m;
minn = min(tmp,minn);
}
printf("%lld\n",(ll)floor(minn));
return 0;
}
【水题纪念|【51nod - 1098】 最小方差(基础数学,公式化简,前缀和,积的前缀和)】总结:由此我们也知道,不仅是值可以求前缀和,任何一个我们想知道的值,只要不带更新操作,都可以求前缀和。
推荐阅读
- AIoT(人工智能+物联网)|程序员的数学【线性代数基础】
- topcoder|Topcoder SRM 661 Div1 Easy: MissingLCM
- HDU 5184 Brackets (卡特兰数)
- 高斯消元
- 扩展欧几里德算法(gcd扩展使用)
- 数学|CF 514D.Nature Reserve 几何,二分,交集
- codeforces|Codeforces Round #665 (Div. 2) C. Mere Array(数学)
- codeforces|Codeforces Round #665 (Div. 2) A. Distance and Axis(思维,数学)
- 数论|Codeforces Global Round 10 B. Omkar and Infinity Clock(数学)