【洛谷P6835】线形生物
题目
题目链接: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;
}