URAL 1828. Approximation by a Progression 数学

1828. Approximation by a Progression

Time limit: 0.5 second
Memory limit: 64 MB
Your are given a sequence of integers  a 1, …,  an. Find an arithmetic progression  b 1, …,  bn for which the value ∑( ai −  bi) 2 is minimal. The elements of the progression can be non-integral.

Input

The first line contains the number  n of elements in the sequence (2 ≤  n ≤ 10 4). In the second line you are given the integers  a 1, …,  an; their absolute values do not exceed 10 4.

Output

Output two numbers separated with a space: the first term of the required arithmetic progression and its difference, with an absolute or relative error of at most 10 −6. It is guaranteed that the answer is unique for all input data.

Samples

input output
4
0 6 10 15
0.400 4.900
4
-2 -2 -2 -2
-2 0





题意 : 给定整数数组 ai。求一个等差数列bi。 等差数列bi要能使 ∑( ai  −  bi ) 2   最小的。输出 b1,d。两者可以是小数。

做法:推公式比较麻烦。步骤如下:

为方便计算 设 第零为b0,方差为d。  那么 bi=b0+i*d 。b1=b0+d。

然后带入 ( ai  −  bi ) 2

带入 bi=b0+i*d 。得到 ∑(b0^2+(i*d)^2+2*b0*i*d-2*b0*ai-2*i*d*ai+ai^2)

把b0提出来  得到  ( b0^2+b0*(2*i*d-2*ai)+(i*d)^2-2*i*d*ai+ai^2)

把d提出来   得到∑ ( i^2* d^2+d*(2*b0*i-2*i*ai)+ b0^2-2*b0*ai+ai^2)

可以发现 两个 分别关于 b0 和d 的二元一次函数都是开口向上的。所以极值落在 -b/2a上。


把∑化到括号里面。

设常数 c1 等于∑bi   ,c2 =∑(i*bi)  c3= ∑i   c4=∑i^2   ∑中i都是从1到n的累加



最后可以化简得到 b0的极值点 b0=-b/2a=(-d*c3+c1)/n,d的极值点  d= =-b/2a=(-b0*c3+c2)/c4。
这两个二元一次方程。 两个式子,可以解出 d =((c1*c3)/n-c2)/(c3*c3/n-c4)   b0=(-d*c3+c1)/n


方程里a1就是等于上面的b0.





#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <string>
#include <iostream>
#include <algorithm>
using namespace std; 
#include <vector> 


int b[11000];
int main()
{
	double n;
	while(scanf("%lf",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			cin>>b[i];
		}


		//c1 bi he
		double c1=0;
		for(int i=1;i<=n;i++)
		{
			c1+=b[i];
		}
		//c2 ibi he
		double c2=0;
		for(int i=1;i<=n;i++)
		{
			c2+=b[i]*i;
		}

		//c3 i he
		double c3=0;
		for(int i=1;i<=n;i++)
		{
			c3+=i;
		}

		//c4 i^2 he
		double c4=0;
		for(int i=1;i<=n;i++)
		{
			c4+=i*i;
		}

		double d=1.0*((c1*c3)/n-c2)/((c3*c3)/n-c4);
		double a=1.0*(-d*c3+c1)/n;
		a+=d;

		if(d<0.000001&&d>-0.000001)
			d=0;
		printf("%lf %lf\n",a,d);

	}
	return 0;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值