一道很新颖的几率DP,我看数据范围还觉得是有指数级别的复杂度的呢spa
记得有人说指望要倒着推,但放在这道题上,就咕咕了吧。code
咱们考虑正着几率DP,设\(fi\)表示将剑升到\(i\)颗星花费的指望,这样咱们能够得出转移:io
而后乍一看很成功,可是这个转移有个致命的问题:在转移2中,式子两边同时出现了\(f_i\)class
这就是传说中的成环DP了,比较通用的方法是利用图论的哲学操做消去这个状况,但我太弱了因此不会方法
但在这里有一种说出来吓死你的智障方法——移项im
咱们连立两个方程,而后将2中的\(f_i\times (1-prob_{i,j})\)移过去便可获得:数据
\(f_i=\frac{(f_{i-1}+c_j-(1-prob_{i,j})\cdot f_{i-1-lose_{i,j}})}{prob[i][j]}\)di
而后就能够直接\(O(7n)\)的DP了,这个复杂度是假的吧co
最后注意一下无解的状况要特判time
CODE
#include<cstdio> using namespace std; typedef double DB; const int N=105; const DB EPS=1e-6,INF=1e99; int c[N],n,lose[10][N]; DB p[10][N],f[10],ans; bool flag=0; inline void miner(DB &x,DB y) { if (x>y+EPS) x=y; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%d",&c[i]); for (i=1;i<=7;++i) { for (flag=0,j=1;j<=n;++j) scanf("%lf",&p[i][j]),flag|=p[i][j]>EPS; if (!flag) return puts("-1"),0; } for (i=1;i<=7;++i) for (j=1;j<=n;++j) scanf("%d",&lose[i][j]); for (i=1,f[1]=INF;i<=7;++i,f[i]=INF) for (j=1;j<=n;++j) if (p[i][j]>EPS) miner(f[i],(DB)(f[i-1]+c[j]-(1-p[i][j])*f[i-1-lose[i][j]])/p[i][j]); printf("%.9lf",f[7]); return 0; }