题解 洛谷 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;
}
posted @ 2020-10-24 19:49  Little09  阅读(114)  评论(0)    收藏  举报