这道题先是很happy的打了个高斯消元
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long double ld;
const int N=200005;
const ld eps=1e-15;
int S,W,A,n;
ld p1,p2;
ld a[N][5],ans;
int main(){
int T; double _p1,_p2;
scanf("%d",&T);
while (T--){
scanf("%d%d%d%lf%lf",&S,&W,&A,&_p1,&_p2); p1=_p1+eps; p2=_p2+eps;
n=S+W;
for (int i=0;i<=n;i++){
if (i-1>=1)
a[i][1]=i-1<=S-A?-p2:-p1;
a[i][2]=1;
if (i+1<n)
a[i][3]=i+1<=S-A?(p2-1.0):(p1-1.0);
}
a[S][0]=1;
for (int i=0;i<n;i++){
a[i+1][2]-=a[i][3]*a[i+1][1]/a[i][2];
a[i+1][0]-=a[i][0]*a[i+1][1]/a[i][2];
a[i+1][1]=0;
}
ans=a[n][0]/a[n][2];
printf("%.15lf\n",(double)(ans+eps));
cl(a);
}
return 0;
}
from decimal import Decimal
from decimal import getcontext
getcontext().prec =65
Zero=Decimal('0.000000000')
One=Decimal('1.000000000')
def AA(i,k):
if k==1:
if i-1>=1:
return ((i-1<=S-A) and p2) or p1
else:
return Zero
else:
if i+1<n:
return ((i+1<=S-A) and _p2) or _p1
else:
return Zero
T=int(input())
for t in range(T):
nums=input().split();
S=int(nums[0])
W=int(nums[1])
A=int(nums[2])
p1=Decimal(nums[3])
p2=Decimal(nums[4])
_p1=One-p1
_p2=One-p2
n=S+W
xx=One
Ans=One
for i in range(n):
xx=One-AA(i,3)*AA(i+1,1)/xx
if i+1>=S:
Ans=Ans/xx
if i+1>S:
Ans=Ans*AA(i+1,1)
print(Ans)
卡过后我仰天长啸 比赛结束后看题解发现自己好傻逼 这么明显的特征根
不过我总觉得题解有那么一点点问题 按照自己想法改过之后的题解应该是这样的
设p(i)为你当前收益为i的时刻条件下能最终获胜的概率
不难列出转移方程,
-S<i<=-A时,p(i)=Pa*p(i+1)+(1-Pa)*p(i-1) .... (1)
-A<i<W时,p(i)=Pb*p(i+1)+(1-Pb)*p(i-1) .... (2)
转移方程(1)、(2)都不难通过特征根的方法求解通项公式;
对于(1)、(2)你会分别获得两个同构的通项公式,不妨假设为f(i)与g(i),f(i)为(1)式子获得,g(i)为(2)式子获得。即
-S<i<=-A时,p(i)=f(i)
-A<i<W时,p(i)=g(i)
f、g中一共有4个未知数,我们可以通过一些边界条件求解,边界包括:
f(-S) = 0 ..... (3)
g(W) = 1 ..... (4)
f(-A) = g(-A) ... (5)
f(-A+1)=g(-A+1) .. (6)
(3)~(6)可以通过高斯消元求解,也可以手工求解并直接写成表达式。
最后注意代码的精度问题。(怕麻烦的话不如用python的decimal)
然后上代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
//typedef __float128 ld;
typedef long double ld;
const ld eps=1e-15;
int S,W,A,n;
ld p1,p2,xa,xb,Ans;
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
int T; double _p1,_p2;
scanf("%d",&T);
while (T--){
scanf("%d%d%d%lf%lf",&S,&W,&A,&_p1,&_p2); p1=_p1+eps; p2=_p2+eps;
xa=(1-p1)/p1; xb=(1-p2)/p2;
Ans=1.0+(xb-1)*(1-pow(xa,W))/((xb-1)*(pow(xa,W)-pow(xa,-A))+pow(xa,-A)*(xa-1)*(1-pow(xb,-S+A)));
printf("%.14lf\n",(double)Ans);
}
return 0;
}