[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%,也算对。

分析

    乍一看这似乎是一道不可做题…… $O(\alpha N^2)$的复杂度,大概再怎么卡常数也是过不了吧?别急……我们看一下这句话……“答案误差不超过5%即可”。瞬间变水题啊好吗……

    考虑到j-i足够大时相邻一定范围内的$\frac{1}{j-i}$相差很小,我们可以随便选一个i来计算j-i,把它作为分母计算一定范围内的i星球对j产生的合力。

    具体地,我们可以随便计算出一个需要精确计算的范围$\delta$,对距离大于这个范围的星球统一计算合力即可。

 

 1 /**************************************************************
 2     Problem: 1011
 3     User: AsmDef
 4     Language: C++
 5     Result: Accepted
 6     Time:1656 ms
 7     Memory:2308 kb
 8 ****************************************************************/
 9  
10 #include <cctype>
11 #include <cstdio>
12 #include <cmath>
13 #include <cstdlib>
14 using namespace std;
15 template<typename T>inline void getd(T &x){
16     char c = getchar(); bool minus = 0;
17     while(!isdigit(c) && c != '-')c = getchar();
18     if(c == '-')minus = 1, c = getchar();
19     x = c - '0';
20     while(isdigit(c = getchar()))x = x * 10 + c - '0';
21     if(minus)x = -x;
22 }
23 /*========================================================*/
24 const int maxn = 100002;
25 const double eps = 1e-12;
26 int N;
27 int main(){
28      
29     //#undef DEBUG
30      
31     double A, M[maxn], S[maxn];
32     #if defined DEBUG
33     freopen("test""r", stdin);
34     freopen("out.txt""w", stdout);
35     #else
36     //freopen("bzoj_1011_planet.in", "r", stdin);
37     //freopen("bzoj_1011_planet.out", "w", stdout);
38     #endif
39     getd(N);
40     int i, j, t, s;
41     double Ans, mid;
42     scanf("%lf", &A);
43     double lim = 1 / A;
44     S[0] = 0;
45     for(i = 1;i <= N;++i)
46         scanf("%lf", M + i), S[i] = S[i-1] + M[i];
47     printf("%.6lf\n", (double)0);
48     for(i = 2;i <= N;++i){
49         Ans = 0;
50         t = (int)(i * A + eps);
51         s = (int)(t - lim);
52         if(s > 1){
53             mid = (int)sqrt((double)(i-1) * (i-s+1));
54             Ans += M[i] * S[s-1] / mid;
55         }
56         else s = 1;
57         for(j = s;j <= t;++j)
58             Ans += M[i] * M[j] / (i - j);
59         printf("%.6lf\n", Ans + eps);
60     }
61      
62     return 0;
63 }
数值近似

 

posted @ 2015-03-26 17:25  Asm.Definer  阅读(159)  评论(0编辑  收藏  举报