题解:P12857 [NERC 2020 Online] Hit the Hay
littlez_meow · · 题解
算上父母有五种状态:婴儿状态
对于时间离散的情况,我们可以直接设
但是非常可惜的是,这里时间是连续的。
不过我们还是可以考虑一个最小时间单位
以
等式两边同时减掉
再同时除掉
左边是导数定义,右边的
同理我们还可以写出
然后是状态
最麻烦的是状态
先研究取到第一项的情况,即
那么上式即:
把第一项减去第二项得到
感性上,
具体地,我们的算法流程应该为:
-
求解如下常系数一阶线性微分方程组:
\left\{\begin{matrix}f_0'(t)=f_0(t)\ln p_0-f_3(t)\ln p_0 \\f_1'(t)=1+f_1(t)\ln p_1-(q_0f_0(t)+(1-q_0)f_2(t))\ln p_1 \\f_2'(t)=1+f_2(t)\ln p_2-f_1(t)\ln p_2 \\f_3(t)=f_1(t) \\f_4(t)=f_2(t) \\f_0(0)=f_1(0)=f_2(0)=f_3(0)=f_4(0)=0\end{matrix}\right. -
二分找到满足
-q_0(f_1(t)-f_0(t))\ln p_1\ge 1 的最小的t 为v ,则上述解的定义域为[0,l] 。 -
求解如下常系数一阶线性微分方程组,其中
t\ge l ,初值为t=l 时与第一步中的解数值相同:\left\{\begin{matrix}f_0'(t)=f_0(t)\ln p_0-f_3(t)\ln p_0 \\f_1'(t)=1+f_1(t)\ln p_1-(q_0f_0(t)+(1-q_0)f_2(t))\ln p_1 \\f_2'(t)=1+f_2(t)\ln p_2-f_1(t)\ln p_2 \\f_3'(t)=f_3(t)\ln p_1-(q_0 f_3(t)+(1-q_0)f_4(t))\ln p_1 \\f_4(t)=f_2(t) \end{matrix}\right. -
答案为
f_0(k) 。
最后的问题是,如何求解一阶线性微分方程组。
第一种方法是求精确解。我们有:
【常系数一阶线性微分方程组解的结构】 对于常系数一阶线性微分方程组
至于特解,官方题解说可以观察到
但是这种方法麻烦完了。既然这题概率不取模,我们完全可以用基于精度的方法。
考虑四阶 Runge–Kutta 法。设
我们取步长
使用拉格朗日中值定理,存在
我们使用
设
取步长
代码
#include<bits/stdc++.h>
#define File(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
#define ll long long
#define F(i,a,b) for(int i(a),i##i##end(b);i<=i##i##end;++i)
#define R(i,a,b) for(int i(a),i##i##end(b);i>=i##i##end;--i)
using namespace std;
const int C=50000;
double k,p0,p1,p2,q0,h;
inline array<double,4> calc1(double x,const array<double,4>&y){
array<double,4>res;
res[0]=y[0]*p0-y[3]*p0;
res[1]=1+y[1]*p1-(q0*y[0]+(1-q0)*y[2])*p1;
res[2]=1+y[2]*p2-y[1]*p2;
res[3]=res[1];
return res;
}
inline array<double,4> calc2(double x,const array<double,4>&y){
array<double,4>res;
res[0]=y[0]*p0-y[3]*p0;
res[1]=1+y[1]*p1-(q0*y[0]+(1-q0)*y[2])*p1;
res[2]=1+y[2]*p2-y[1]*p2;
res[3]=y[3]*p1-(q0*y[3]+(1-q0)*y[2])*p1;
return res;
}
array<double,4> operator+(const array<double,4>&a,const double&b){return {a[0]+b,a[1]+b,a[2]+b,a[3]+b};}
array<double,4> operator+(const array<double,4>&a,const array<double,4>&b){return {a[0]+b[0],a[1]+b[1],a[2]+b[2],a[3]+b[3]};}
array<double,4> operator*(const double&b,const array<double,4>&a){return {a[0]*b,a[1]*b,a[2]*b,a[3]*b};}
double x[C*2];
array<double,4>y[C*2];
inline void solve1(){
y[0]={0,0,0,0};
array<double,4>k1,k2,k3,k4;
F(i,1,C){
k1=calc1(x[i-1],y[i-1]);
k2=calc1(x[i-1]+h/2,y[i-1]+h/2*k1);
k3=calc1(x[i-1]+h/2,y[i-1]+h/2*k2);
k4=calc1(x[i-1]+h,y[i-1]+h*k3);
y[i]=y[i-1]+h/6*(k1+2*k2+2*k3+k4);
}
}
inline void solve2(int l){
array<double,4>k1,k2,k3,k4;
F(i,l,C){
k1=calc2(x[i-1],y[i-1]);
k2=calc2(x[i-1]+h/2,y[i-1]+h/2*k1);
k3=calc2(x[i-1]+h/2,y[i-1]+h/2*k2);
k4=calc2(x[i-1]+h,y[i-1]+h*k3);
y[i]=y[i-1]+h/6*(k1+2*k2+2*k3+k4);
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int T;
cout<<fixed<<setprecision(12);
for(cin>>T;T;--T){
cin>>k>>p0>>p1>>p2>>q0;
p0=log(p0),p1=log(p1),p2=log(p2);
h=k/C;
F(i,0,C) x[i]=i*h;
solve1();
int l=0,r=C+1;
while(l<r){
int mid=(l+r)>>1;
if(-q0*(y[mid][1]-y[mid][0])*p1>=1) r=mid;
else l=mid+1;
}
if(l!=C+1) solve2(l);
cout<<y[C][0]<<"\n";
}
return 0;
}