萌萌哒博主开始做PE啦!
之后的PE应该会良心给答案。
这次的是75.44817535。
感觉被卡精度卡得昏天黑地。
注意到JA的前缀和是
∑i=1n∑j=1n(ij)2ij
JB的前缀和是
∑i=1n∑j=1n1(ij)j
两个都要交换i和j。分开考虑。
第一个
∑j=1n∑ni=1(ij)2ij
设
Fi=∑i=1n(ij)2i
将上面的那个组合数拆成
(i−1j−1)+(ij−1)
我们可以方便地得到
Fi−Fi−1=(n+1i)2n
第二个式子比较trival,我们将i,j调换顺序后会出现一个
∑i=1n1(ij)
冷静一下,这不是小学奥数中的裂项吗?暴力裂项大法好!
之后的式子就不写了,留给读者自己推导吧(其实是博主觉得写Latex太麻烦了)
当然注意特判j=1的情况,这个是一个调和级数数列之和,没办法裂项。
这样计算就是线性了。但是精度会炸飞。我们可以将乘除在log下计算,加减的时候exp回去。当然不要试图预处理阶乘的对数,你会MLE+炸精度,正确姿势是递推。
附代码。
#include <bits/stdc++.h>
using namespace std;
int n;
int main()
{
scanf("%d", &n);
long double ans = 0, tmp = 2 - 1 / pow(2.0, n), f = -log(2.0) * n;
for(int i = 1; i <= n; i++) {
f = f + log(n + 2 - i) - log(i);
tmp -= exp(f);
ans += tmp / i;
}
f = -log(n);
for(int i = 2; i <= n; i++) {
ans += 2.0 / (i - 1) - exp(f);
f = f + log(i - 1) - log(n - i + 1);
}
printf("%.15lf\n", (double) ans + 1.0 / n);
return 0;
}
Thread里的众人的智慧真是无穷啊。。。
大众做法是考虑JA(n)-JB(n)在n很大的时候这个值十分的小(否则为什么会有PE 568),所以说卡一发精度就暴力过了。
get了几个公式:
这里是一堆干掉组合数的式子及证明
这里是第三个式子的证明
∑r>=012r+1(n+12r+1)=∑i=0n2ii+1
∑r>=112r(n+12r)=∑i=0n2i−1i+1
∑k=1n1k(nk)=12n∑k=1n2kk