HNOI2008 遥远的行星

传送门

这完全是一道bug题……

用普通的方法来想,我们肯定是要枚举每一颗行星的,之后对于每颗行星,我们计算一下能影响到它的行星。从行星的引力计算公式来看,这样无论如何都无法用有效的算法求解。分子可以用前缀和,但是分母必须一个一个算,我们不可能全部通分一遍再计算的……而且那样的复杂度和原来也是一样。

那怎么办?我们注意到,他要求误差不超过5%即可。……这么大的误差都允许的话,就可以使用某些bug玄学算法。考虑到分母特别棘手,所以不如我们直接取一个区间之内的中位数为这个区间每次计算的分母,这样的话你只需要处理分子前缀和,之后依次枚举就可以了……。

复杂度O(n),神奇水过……因为A是在0.01~0.35之间的,所以其实把区间长度取到100大概就能过(也可以更小不过要注意别T了)

(好吧,这可能是假题解……)

代码很短。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define rep(i,a,n) for(ll i = a;i <= n;i++)
#define per(i,n,a) for(ll i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}

const int T = 100;
int n;
double a;
ll m[maxn], sum[maxn];

int main()
{
    n = read();
    scanf("%lf", &a);
    rep(i,1,n) m[i] = read(),sum[i] = sum[i - 1] + m[i];
    rep(i,1,n)
    {
        int x = i * a;
        double ans = 0;
        int L = 1, R = T;
        while(R <= x)
        {
            ans += (sum[R] - sum[L - 1]) * m[i] / (i - ((L + R) >> 1));
            L += T,R += T;
        }
        rep(j,L,x) ans += m[j] * m[i] / (i - j);
        printf("%.6lf\n", ans);
    }
    return 0;
}

 

posted @ 2018-08-18 00:13  CaptainLi  阅读(128)  评论(0编辑  收藏  举报