1. 程式人生 > >【BZOJ1011】[HNOI2008]遙遠的行星

【BZOJ1011】[HNOI2008]遙遠的行星

spl zoj += clas scan max stream names class

【BZOJ1011】[HNOI2008]遙遠的行星

題面

bzoj

洛谷

題解

亂搞題。。。

主要是要利用“只要結果的相對誤差不超過5%即可”這個條件。

對於第\(i\)個行星,我們記\(x=\lfloor a*i\rfloor\),對他有貢獻的區間為\([1,x]\)

我們統計時,將區間\([1,x]\)分塊統計,設塊大小為\(len\)

\(x\leq len\),暴力即可。

\(x>T\),將\([1,x]\)分為很多小區間,則每個小區間\([x,y]\)的貢獻可看作

\[ \frac{M_i*\sum_{j=x}^yM_j}{i-\frac{x+y}{x}} \]

由於\(0.01<a\leq 0.35\)

,可知誤差不超過\(0.02\)

代碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
typedef long double real; 
const int MAX_N = 1e5 + 5, LEN = 320; 
int N; 
real A, M[MAX_N], sum[MAX_N]; 

int main () {
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin);
#endif 
    scanf("%d%Lf", &N, &A); 
    for (int i = 1; i <= N; i++) scanf("%Lf", M + i); 
    for (int i = 1; i <= N; i++) { 
        sum[i] = sum[i - 1] + M[i]; 
        real ans = 0; 
        int r = i * A; 
        for (int j = r; j > max(r - LEN, 0); j--) ans += M[i] * M[j] / (i - j); 
        if (r > LEN) { 
            r -= LEN; 
            int t = sqrt(r), l; 
            while (r) { 
                l = max(r - t, 0); 
                ans += M[i] * (sum[r] - sum[l]) / (i - (r + l) / 2);
                r = l; 
            } 
        }
        printf("%0.5Lf\n", ans); 
    } 
    return 0; 
} 

【BZOJ1011】[HNOI2008]遙遠的行星