题解 洛谷 P6835 [Cnoi2020]线形生物
感觉这道题好像出的水了点,像我这种对期望一窍不通的菜鸡也可以推出来。我的思路好像和大家不太一样(更简单一点吧)……但是好歹过了,大家可以参考一下。
我们设要通过第 \(x\) 个点需要的期望步数为 \(E(x)\)。那么我们可以根据定义推出 \(E(x)\) 的表达式:
\[E(x)=\dfrac{n+\sum \sum_{i=t_x}^{x}E(i)}{n}
\]
在这里,\(t_x\) 表示所有 \(x\) 的返祖点。第一个求和符号枚举的是它的所有返祖边,第二个求和是要求从 \(t_x\) 走到 \(x\) 的期望步数。显而易见,第二个求和可以前缀和优化。
我们令 \(S(x)=\sum_{i=1}^{x}E(i)\)。那么原式可以写为:
\[E(x)=\dfrac{n+(n-1)\times S(x)-\sum S(t_x-1)}{n}
\]
把 \(S(x)\) 改为 \(E(x)+S(x-1)\),再移项,就可以得到 \(E(x)\) 的公式:
\[E(x)=n+(n-1)\times S(x-1)-\sum S(t_x-1)
\]
至此可以 \(O(n+m)\) 计算了。维护一下 \(E\) 和 \(S\),从 \(1\) 开始枚举就可以了。
献上丑陋的代码。
#include<bits/stdc++.h>
using namespace std;
int x,y;
long long g[1000001],ans;
const long long mod=998244353;
int h[1000001],t[1000001],nxt[1000001],cnt;
long long E[1000001],S[1000001];
inline int read()
{
char C;
int F=1,ANS=0;
while (C<'0'||C>'9')
{
if (C=='-') F=-1;
C=getchar();
}
while (C>='0'&&C<='9')
{
ANS=ANS*10+C-'0';
C=getchar();
}
return F*ANS;
}
inline void add(int x,int y)
{
t[++cnt]=y;
nxt[cnt]=h[x];
h[x]=cnt;
}
int main()
{
int id,n,m;
cin >> id >> n >> m;
for (int i=1;i<=m;i++)
{
int x,y;
x=read(),y=read();
g[x]++;
add(x,y);
}
for (int i=1;i<=n;i++)
{
E[i]=(g[i]+1+g[i]*(S[i-1]))%mod;
long long res=0;
for (int j=h[i];j;j=nxt[j])
{
res=(res+S[t[j]-1])%mod;
}
E[i]-=res;
E[i]=(E[i]+mod)%mod;
S[i]=(S[i-1]+E[i])%mod;
}
cout << S[n];
return 0;
}