个人感觉是非常无趣的一题。
一眼看过去期望 d p dp dp,推了半天发现没办法写
然后发现 v > 0.1 v>0.1 v>0.1,呵呵
于是你发现,就算最优情况下轮流消耗 c c c和 m m m,然而 c , m c,m c,m还是会掉的非常快
因为有一半贡献都会给到 p p p
而这题恰好是不需要取模,只要求精度在 1 0 − 6 10^{-6} 10−6内
换句话说,若某个状态被转移到的概率比 1 0 − 6 10^{-6} 10−6还小,那么是不会影响到答案的
显然这样的状态并不多,我们直接[递归/bfs]模拟即可
PS:
很多人可能会直接用状态和 0 0 0作比较,然而 d o u b l e double double精度是玄学而且很低的,设置 e p s = 1 0 − 6 eps=10^{-6} eps=10−6比较安全。如果你喜欢, e p s eps eps设置的更小也没有问题
#include <bits/stdc++.h>
using namespace std;
#define double long double
const int maxn = 3e5+10;
const double eps = 1e-6;
int t,n,m,a[maxn];
struct P
{
double c,m,p,pro;
bool operator < ( const P&tmp ) const
{
return pro>tmp.pro;
}
};
priority_queue<P>q;
signed main()
{
cin >> t;
while( t-- )
{
double c,m,p,v; cin >> c >> m >> p >> v;
double ans = 1.0;
int tim = 0;
q.push( P{c,m,p,1.0} );
while( !q.empty() && tim<=10000000 )
{
tim++;
P u = q.top(); q.pop();
ans += u.pro*( u.c+u.m );//这次选到
if( u.c>eps )
{
P temp = u; double zhi = min( u.c,v );
temp.pro = u.pro*u.c;
if( u.m>eps )
temp.c -= zhi, temp.m += zhi/2.0, temp.p += zhi/2.0;
else
temp.c -= zhi, temp.p += zhi;
q.push( temp );
}
if( u.m>eps )
{
P temp = u; double zhi = min( u.m,v );
temp.pro = u.pro*u.m;
if( u.c>eps )
temp.m -= zhi, temp.c += zhi/2.0, temp.p += zhi/2.0;
else
temp.m -= zhi, temp.p += zhi;
q.push( temp );
}
}
while( !q.empty() ) q.pop();
printf("%.11Lf\n",ans );
}
}