P6154 游走 概率dp

传送门

题意:
在这里插入图片描述
思路: 给你个 D A G DAG DAG,由于每一条路径出现概率相等,那么期望就是 总 长 度 路 径 个 数 \frac{总长度}{路径个数} 。设 f [ i ] f[i] f[i]表示到 i i i这个点的总长度, g [ i ] g[i] g[i]表示到 i i i这个点路径的总个数。那么转移方程也比较好想了: f [ i ] = ∑ e d g e ( j , i ) ( f [ j ] + g [ j ] ) f[i]=\sum_{edge(j,i)}(f[j]+g[j]) f[i]=edge(j,i)(f[j]+g[j]) g [ i ] = ∑ e d g e ( j , i ) g [ j ] + 1 g[i]=\sum_{edge(j,i)}g[j]+1 g[i]=edge(j,i)g[j]+1
g [ i ] g[i] g[i]要加一是因为要加上自己到自己的,最终答案为 ∑ f [ i ] ∑ g [ i ] \frac{\sum f[i]}{\sum g[i]} g[i]f[i]

//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=1000010,mod=998244353,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m;
int d[N];
LL f[N],g[N];
vector<int>v[N];

LL qmi(LL a,LL b)
{
    LL ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

void topsort()
{
    queue<int>q;
    for(int i=1;i<=n;i++) if(!d[i]) q.push(i),g[i]=1;
    while(q.size())
    {
        int u=q.front(); q.pop();
        for(auto x:v[u])
        {
            (f[x]+=f[u]+g[u])%=mod;
            (g[x]+=g[u])%=mod;
            if(--d[x]==0) q.push(x),g[x]++;
        }
    }
    LL ans1=0,ans2=0;
    for(int i=1;i<=n;i++) (ans1+=f[i])%=mod,(ans2+=g[i])%=mod;
    printf("%lld\n",ans1*qmi(ans2,mod-2)%mod);
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b; scanf("%d%d",&a,&b);
        v[a].pb(b); d[b]++;
    }
    topsort();



	return 0;
}
/*

*/









  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值