[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
3
5
6
2
4
Sample Output
0.000000
0.000000
0.000000
1.968750
2.976000
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 }
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 }