LINK

个人感觉是非常无趣的一题。

一眼看过去期望 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} 106

换句话说,若某个状态被转移到的概率比 1 0 − 6 10^{-6} 106还小,那么是不会影响到答案的

显然这样的状态并不多,我们直接[递归/bfs]模拟即可

PS:

很多人可能会直接用状态和 0 0 0作比较,然而 d o u b l e double double精度是玄学而且很低的,设置 e p s = 1 0 − 6 eps=10^{-6} eps=106比较安全。如果你喜欢, 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 );
	}
}