若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的整数部分。
链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1098
都是通过递推的,但我的方法没化简到底,所以比别人慢了点;
先放我的代码
#include<algorithm> #include<cstdlib> #include<iostream> #include<cstring> #include<cstdlib> #define getrand(a,b) (int)((rand()/33000.0)*((b)-(a)+1))+(a) using namespace std; typedef long long LL; const int maxnn=100+5; const int maxn=100000+5; const int mod=1e9+7; double num[10001]; int main() { int m,n;LL ans; double a=0,b=0,k,derta,x;//a:方差*n,b:n个数的和,k:均值 cin>>m>>n; //derta:均值变化量 for(int i=0;i<m;i++){ cin>>num[i]; } sort(num,num+m); // for(int i=0;i<m;i++) // cout<<num[i]<<‘ ‘; // cout<<endl; int f,l;//首位标号 f=0;l=0; for(int i=0;i<n;i++)b+=num[i]; k=b/(double)n; // cout<<k<<endl; while(l<n){ x=num[l]-k; a+=x*x; l++; } l--;ans=a; double x1;//临时变量 m=m-1; while(l<m){ l++; a-=(num[f]-k)*(num[f]-k); // cout<<a<<‘ ‘;//1 b-=num[f++]; // cout<<b<<‘ ‘;//2 x1=k; k=(b+num[l])/(float)n; // cout<<k<<‘ ‘;//3 derta=k-x1; // cout<<derta<<‘ ‘;//4 a=a-derta*(b-(n-1)*x1)*2+(n-1)*derta*derta; // cout<<a<<‘ ‘;//5 b+=num[l]; // cout<<b<<‘ ‘;//6 a+=(num[l]-k)*(num[l]-k); // cout<<a<<‘ ‘<<endl; if(a<ans)ans=a; } cout<<ans<<endl; return 0; }
别人的较好代码
#include <iostream> #include<stdio.h> #include<algorithm> #define MAX_N 10001 int a[MAX_N]; using namespace std; int main() { int M,N; scanf("%d%d", &M,&N); for(int i=0; i<M; i++) scanf("%d", a+i); sort(a, a+M); long long sqrSum = 0; long long sum = 0; for(int i=0; i<N; i++) { sqrSum += a[i]*a[i]; sum += a[i]; } long long ans = sqrSum-sum*sum*1.0/N; for(int i=N; i<M; i++) { sqrSum -= a[i-N]*a[i-N]; sum -= a[i-N]; sqrSum += a[i]*a[i]; sum += a[i]; ans = min(ans, (long long)(sqrSum-sum*sum*1.0/N)); } printf("%lld\n", ans); return 0; }