题意
直线上
n
颗行星,
请计算每颗行星的受力,只要结果的相对误差不超过5%即可.
0.01≤a≤0.35
分析
设
gi
表示第
i
颗行星受
直接计算 fi 的时间复杂度为 O(n) ,总的时间复杂度为 O(n2) ,很明显会超时。
题目中提及“只要结果的相对误差不超过5%即可”,说明我们求出的值不用特别的精确,那么就考虑用近似算法进行估算。
考虑用递推的方法,把所求尽可能凑出已知量。
假设我们已经求出
则
对于括号内的第二部分,注意
g
值具有的单调性,所以总共
关键处理好括号内的第一部分即可。
第一部分可以这样估算:
所以
为了使答案更加精确,我们需求更多的准确值。
对于
i≤T
,我们直接用暴力算法求解。
对于
i>T
,我们用
fi−T
来估算
fi
。
T
的取值应尽可能大,而且暴力算法不会超时。
我的
还有就是要注意取整不能直接用
int(A∗j)
,可以使用
int(A∗j+EPS)
,或者使用函数
floor(A∗j)
。
浮点误差会导致答案错误。
小结
给定很少输入,求 1 到
N 的某个函数值的问题,通常有两种方法:直接求、递推。浮点数取整直接用 (int)a 会因为浮点误差带来结果的偏差,应使用 floor(a) 更精确。
关于这类估算的问题
①特征:“结果的相对误差不超过5%”之类的话,再给个SPJ;
②原则:能精确尽可能精确;
③对于不超时的精确部分,就让它保留,对于会超时的精确部分,才考虑估算;
④在用递推的方法时,对于小数据可以先暴力求,对于大数据再估算;
⑤估算的一种常见方法:取平均数、中位数、众数之类的。
代码
#include <cstdio>
#include <cmath>
const int N=100010;
const int T=1000;
const double EPS=1e-7;
int n;
double a;
double m[N];
int g[N];
double w[N];
int main(void)
{
scanf("%d%lf",&n,&a);
for (int i=1;i<=n;i++) scanf("%lf",&m[i]);
for (int i=1;i<=n;i++) g[i]=floor(a*i);
for (int i=1;i<=T;i++)
{
for (int j=1;j<=g[i];j++)
w[i]+=m[j]/(i-j);
w[i]*=m[i];
}
double tmp;
for (int i=1;i<=n-T;i++)
{
tmp=0;
tmp=tmp+w[i]*(i-g[i]/2)/m[i]/(i+T-g[i]/2);
for (int j=g[i]+1;j<=g[i+T];j++) tmp=tmp+m[j]/(i+T-j);
w[i+T]=tmp*m[i+T];
}
for (int i=1;i<=n;i++)
printf("%0.6lf\n",w[i]);
return 0;
}