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}\)
-
若\(\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)\)时间内询问
-
显然\(\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;
}