bzoj3640: JC的小苹果
http://www.lydsy.com/JudgeOnline/problem.php?id=3640
dp[i][j] 表示i滴血到达j的概率
dp[i][j] = Σ dp[i+val[i]][k]/d[k]
将第一维看做层次
那么同层之间需要高斯消元解决
对每一层都做一次是 hp*n^3
但是不同层次之间只有常数列是不一样的
记录第一次将系数矩阵消成上三角矩阵的过程
每次修改系数列,只模拟回代的过程
hp* n^2
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define N 151 #define M 5001 #define K 10001 int val[N]; int front[N],to[M<<1],nxt[M<<1],tot; int d[N]; double a[N+1][N+1],b[N+1]; struct node { int i; double t; }e[N][N]; int cnt[N]; double dp[K][N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; } void pre(int n) { double t; for(int i=1;i<=n;++i) { for(int j=i+1;j<=n;++j) { t=a[j][i]/a[i][i]; for(int k=i;k<=n;++k) a[j][k]-=a[i][k]*t; e[j][++cnt[j]].i=i; e[j][cnt[j]].t=t; } } } void gauss(int n,int m) { for(int i=n;i>=1;--i) { for(int j=i+1;j<=n;++j) b[i]-=a[i][j]*dp[m][j]; dp[m][i]=b[i]/a[i][i]; } } int main() { int n,m,hp; read(n); read(m); read(hp); for(int i=1;i<=n;++i) read(val[i]); int u,v; for(int i=1;i<=m;++i) { read(u); read(v); add(u,v); d[u]++; if(u!=v) add(v,u),d[v]++; } for(int i=1;i<=n;++i) { a[i][i]=1; if(val[i]) continue; for(int j=front[i];j;j=nxt[j]) if(to[j]!=n) a[i][to[j]]-=1.0/d[to[j]]; } pre(n); for(int i=hp;i;--i) { memset(b,0,sizeof(b)); if(i==hp) b[1]=1; for(int j=1;j<=n;++j) if(val[j] && i+val[j]<=hp) for(int k=front[j];k;k=nxt[k]) if(to[k]!=n) b[j]+=dp[i+val[j]][to[k]]/d[to[k]]; for(int j=1;j<=n;++j) for(int k=1;k<=cnt[j];++k) b[j]-=b[e[j][k].i]*e[j][k].t; gauss(n,i); } double ans=0; for(int i=1;i<=hp;++i) ans+=dp[i][n]; printf("%.8lf",ans); }