题目

题目链接:https://www.luogu.com.cn/problem/P6835
线形生物要从 \(1\) 号台阶走到 \(n+1\) 号台阶。

最开始,\(1,2,3,\ldots,n\) 号台阶都有一条连向下一台阶的有向边 \(i\rightarrow i+1\)

之后 Cirno 加入了 \(m\)返祖边 \(u_i \rightarrow v_i (u_i \ge v_i)\),它们构成了一个返祖图

线形生物每步会 等概率地 选取当前台阶的一条出边并走向对应的台阶。

当走到 \(n+1\) 号台阶时,线形生物就会停止行走。

同时,Cirno 会统计线性生物总共走的步数,记作 \(\delta\)

Cirno 想知道 \(E(\delta)\)(即 \(\delta\)数学期望)对 \(998244353\) 取模后的结果。

思路

\(f[i]\) 表示从 \(i\) 走到 \(i+1\) 的期望步数,\(g[i]=sum^{i}_{j=1}f[j]\)。那么答案即为 \(g[n]\)
\(c[i]\) 表示点 \(i\) 往回走的路径数量。那么有

\[f[i]=\frac{\sum^{c[i]}_{j=1}(g[i]-g[to[j]-1]+1)+1}{c[i]+1} \]

\(g[i]\) 拆成 \(g[i-1]+f[i]\),解方程得

\[f[i]=c[i]g[i-1]+c[i]+1-\sum^{c[i]}_{j=1}g[to[j]] \]

时间复杂度 \(O(n)\)

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1000010,MOD=998244353;
int n,m,WYCAKIOI,tot,head[N],cnt[N];
ll f[N],g[N];

ll fpow(ll x,int k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

struct edge
{
	int next,to;
}e[N];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&WYCAKIOI,&n,&m);
	for (int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); cnt[x]++;
	}
	for (int i=1;i<=n;i++)
	{
		f[i]=(cnt[i]+1LL+cnt[i]*g[i-1])%MOD;
		for (int j=head[i];~j;j=e[j].next)
			f[i]=(f[i]-g[e[j].to-1]+MOD)%MOD;
		g[i]=(g[i-1]+f[i])%MOD;
	}
	printf("%lld",g[n]);
	return 0;
}