[BZOJ1011] [HNOI2008] 遥远的行星

Description

  直线上N颗行星,X=i处有行星i,行星J受到行星I的作用力,当且仅当i<=AJ.此时J受到作用力的大小为 Fi->j=
Mi*Mj/(j-i) 其中A为很小的常量,故直观上说每颗行星都只受到距离遥远的行星的作用。请计算每颗行星的受力
,只要结果的相对误差不超过5%即可.

Input

  第一行两个整数N和A. 1<=N<=10^5.0.01< a < =0.35,接下来N行输入N个行星的质量Mi,保证0<=Mi<=10^7

Output

  N行,依次输出各行星的受力情况

Sample Input

5 0.3
3
5
6
2
4

Sample Output

0.000000
0.000000
0.000000
1.968750
2.976000

HINT

  精确结果应该为0 0 0 2 3,但样例输出的结果误差不超过5%,也算对 

Source

Solution

  按题意模拟,复杂度是$O(an^2)$的,然而好像并没有什么优化方法

  突破口是“误差不超过5%”这句话

  令$i=\lfloor{aj}\rfloor$

  对于星球$j$,我们要求的和式为$\displaystyle\sum_{k=1}^{i}\frac{m_k*m_j}{j-k}$

  当$j$很大时,$i$也不会太大,我们可以把式子化成$\displaystyle\sum_{k=1}^{i}\frac{m_k*m_j}{j-0.5i}$

  用$sum_i$表示前$i$个星球的质量和,那么和式可以化成$\displaystyle\frac{sum_i*m_j}{j-0.5i}$

  这样我们就可以少用一个变量$k$,复杂度就降为了$O(n)$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 double m[100005], sum[100005];
 4 int main()
 5 {
 6     int n;
 7     double a, ans;
 8     scanf("%d%lf", &n, &a);
 9     for(int j = 1; j <= n; ++j)
10     {
11         int i = (int)(a * j + 1e-8);
12         scanf("%lf", m + j);
13         ans = 0;
14         if(j <= 500)
15             for(int k = 1; k <= i; ++k)
16                 ans += m[k] * m[j] / (j - k);
17         else
18             ans = sum[i] * m[j] / (j - i / 2);
19         printf("%f\n", ans);
20         sum[j] = sum[j - 1] + m[j];
21     }
22     return 0;
23 }
View Code
posted @ 2016-06-24 23:48  CtrlCV  阅读(1046)  评论(0编辑  收藏  举报