返回顶部
扩大
缩小

BZOJ1011 [HNOI2008]遥远的行星

题目链接

题意:

对于每个\(i\),求\(\sum_{j=1}^{A\times i} \frac{m_i\times m_j}{i - j}\)

做法:

第一眼看上去像平衡树,但每一项都与当前i有关,且不可分开考虑(分母\(i-j\)

再看题面发现特殊条件:相对误差不超过 5% 即可(通常应该是误差在\(10^x\)之内),较为特殊

相对误差限制通常是在较大的情况下允许误差范围越大

如斯特林公式:\(n!\sim \sqrt{2n\pi} * (\frac{n}{e})^n\)\(\sim\)限制的是两边的比值

于是想到在\(n\)较小的时候暴力,在\(n\)较大的时候估计

\(\sum_{j=1}^{A\times i} \frac{m_i\times m_j}{i - j}\) = \(m_i \times \sum_{j=1}^{A\times i} \frac{m_j}{i - j}\)

  1. \(\forall j, i-j=k\)\(m_i \times \sum_{j=1}^{A\times i} \frac{m_j}{i - j}\) = \(m_i / k \times \sum_{j=1}^{A\times i} m_j\),可用前缀和在\(O(1)\)时间内询问

  2. 显然\(\forall j1,j2(j1\neq j2,j1,j2\in[1,A\times i]), i-j1 \neq i-j2\),于是近似得认为$i-1 \approx i - A\times i; \Rightarrow i-1 \approx i - (A \times i) ; / 2 \approx A\times i; $

于是可用\(1.\)中的方法处理\(2.\),时间复杂度:\(O(n^2)(n\leq 2000) \; or \;O(n)\)

代码:

#include <iostream>
#include <cstdio>
 
using namespace std;
 
const int N = 1e5 + 5;
 
int n;
long double a, m[N], s[N];
 
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> a;
    for (int i = 1; i <= n; ++i)
        cin >> m[i];
    for (int i = 1; i <= n; ++i)
        s[i] = s[i - 1] + m[i];
    int p = min(2000, n);
    for (int i = 1; i <= p; ++i)
    {
        int g = (int)(a * (1.0 * i));
        long double ans = 0;
        for (int j = 1; j <= g; ++j)
            ans += (m[i] * m[j]) / (i - j) * 1.0;
        printf("%.20LF\n", ans);
    }
    for (int i = p + 1; i <= n; ++i)
    {
        int g = (int)(a * (1.0 * i));
        if (g == 0)
            cout << 0 << endl;
        else
        {
            long double ar = a / (1.0 - a);
            printf("%.20LF\n", s[g] * m[i] / (i - (a * i) / 2.0));
        }
    }
    return 0;
}
posted @ 2019-11-24 13:31  Asasino  阅读(88)  评论(0编辑  收藏  举报