这题公式不难推,就是控制精度的问题。因为公式是一些项求和,这里每一项都是接近于1的数,但是每一项里包含一个组合数和一个p^n,如果每次直接把p^n乘进去就会使数字太小,如果一直留到最后乘,可能中间就溢出了。解决的办法就是根据中间变量的大小动态地乘p^k,防止溢出,也防止数字太小丢精度
离比赛结束已经有一段时间了,今天再来看这题,打算把它A掉,结果查了一下解题报告,发现这题其实有不需要控制精度的方法!!!唉,当时太SB了,这种方法居然都没想到,花了一两个小时去控制精度。
其实只要在运算过程中全部取对数就可以了。。。。啊啊啊。。。
/* * hdu4465/win.cpp * Created on: 2012-11-19 * Author : ben */ #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <cctype> #include <iostream> #include <algorithm> #include <queue> #include <set> #include <map> #include <stack> #include <string> #include <vector> #include <deque> #include <list> #include <functional> #include <numeric> #include <bitset> using namespace std; const int MAXN = 200100; double c[MAXN], pq[MAXN], qp[MAXN]; double work(int n, double p) { double ret = 0; double logp = log(p), log1p = log(1 - p); c[0] = 0; pq[0] = (n + 1) * logp; qp[0] = (n + 1) * log1p; ret += n * exp(c[0] + pq[0]); ret += n * exp(c[0] + qp[0]); for(int k = 1; k < n; k++) { c[k] = c[k - 1] + log(n + k) - log(k); pq[k] = pq[k - 1] + log1p; qp[k] = qp[k - 1] + logp; ret += (n - k) * exp(c[k] + pq[k]); ret += (n - k) * exp(c[k] + qp[k]); } return ret; } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif int t = 1, n; double p; while(scanf("%d%lf", &n, &p) == 2) { printf("Case %d: %.6f\n", t++, work(n, p)); } return 0; }