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);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8605444.html