hdu7016 / 2021“MINIEYE杯”中国大学生算法设计超级联赛(5)1005 Random Walk 2(高斯消元)

https://acm.hdu.edu.cn/showproblem.php?pid=7016

 

题意:

n个点的有向完全图,在图上游走

每次以p[i][j]的概率从i走向j

如果某次在原地没有动,那么游走结束

对所有i j回答起点在i,游走到j结束的概率

 

设起点在s

用常见的解决图上随机游走问题的方法

设f[j]表示从起点走到j,还能继续走下去的概率

f[j]=∑ f[k]*p[k][j]  (k≠j)   + p[s][j]  (s≠j)

k相当于是枚举走到j的前一步,k不能等于j,因为要可以继续走下去

后面的p[s][j]是没有前一步,j就是第一步,直接s到j,同理不能原地踏步

a[j]表示从起点走到j,游走结束的概率

a[j]=f[j]*p[j][j] + p[j][j] (s=j)

后面的p[j][j]是从起点走了一步就走不下去的概率

然后用高斯消元可以O(n^3)求出f,进而求出a

但这是一个起点,再枚举起点就是O(n^4)了

我们发现当终点相同时,f的式子只有最后面的常数项p不一项

也就是说对于所有的f[i][j],i∈[i,n],j相同(不同起点同终点),高斯消元的系数矩阵是一样的,增广矩阵只有最后一列是不同的

那么我们可以把所有增广矩阵的最后一列放到一起,变成n*2n的增广矩阵

这样解出来的增广矩阵第i行第n+j列就是以f[j][i]

 

hdu不知道为啥

f[j][k]-=t*f[i][k]%mod;
if(f[j][k]<0) f[j][k]+=mod;

这样写一直TLE

把下头换成三目运算符就跑得飞快

f[i][k]=f[i][k]<0 ? f[i][k]+mod : f[i][k];

 

#include<bits/stdc++.h>

using namespace std;

#define N 302
#define mod 998244353

int n,m;

int w[N][N],p[N][N]; 

typedef long long LL;

LL f[N][N<<1];

inline LL poww(LL a,LL b)
{
    LL c=1;
    for(;b;a=a*a%mod,b>>=1)
        if(b&1) c=c*a%mod;
    return c;
}

inline void gauss()
{
    int r;
    LL inv,t;
    for(int i=1;i<=n;++i)
    {
        r=i;
        while(r<=n && !f[r][i]) ++r;
        if(r>n) continue;
        if(r!=i) swap(f[i],f[r]);
        inv=poww(f[i][i],mod-2);
        for(int j=i;j<=m;++j) f[i][j]=f[i][j]*inv%mod;
        for(int j=i+1;j<=n;++j)
        {
            t=f[j][i];
            for(int k=i;k<=m;++k) 
            {
                f[j][k]-=t*f[i][k]%mod;
                //if(f[j][k]<0) f[j][k]+=mod;
                f[j][k]=f[j][k]<0 ? f[j][k]+mod : f[j][k];
            }
        }
    }
    for(int i=n;i;--i)
        for(int k=n+1;k<=m;++k)
        {
            for(int j=i+1;j<=n;++j)
            {
                f[i][k]-=f[i][j]*f[j][k]%mod;
                f[i][k]=f[i][k]<0 ? f[i][k]+mod : f[i][k];
            }
        }
}

int main()
{
    int T,sum,ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                 scanf("%d",&w[i][j]);
        for(int i=1;i<=n;++i)
        {
            sum=0;
            for(int j=1;j<=n;++j) sum+=w[i][j];
            sum=poww(sum,mod-2);
            for(int j=1;j<=n;++j) p[i][j]=1ll*w[i][j]*sum%mod;
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
                if(j!=i) f[i][j]=mod-p[j][i];
            f[i][i]=1;
            for(int j=1;j<=n;++j) 
                if(i!=j) f[i][n+j]=p[j][i];
            f[i][n+i]=0;
        }
        m=n<<1;
        gauss();    
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j) 
            {
                ans=f[j][n+i]*p[j][j]%mod;
                if(i==j) ans=(ans+p[j][j])%mod;
                printf("%d%c",ans,j==n ? '\n' : ' ');
            }
        }
    }
}

 

posted @ 2021-08-22 08:27  TRTTG  阅读(110)  评论(0编辑  收藏  举报