【Codeforces gym102268E Expected Value】【生成函数+Berlekamp-Massey算法】

题意

给一个 n n n个点的平面图,问从 1 1 1随机游走到 n n n的期望步数。
n ≤ 3000 n\le 3000 n3000

分析

注意到是平面图,所以边数不超过 3 n − 6 3n-6 3n6
p i p_i pi表示走了 i i i步到 n n n的概率,则 p i p_i pi是一个 n n n阶线性递推。
先递推出 p i p_i pi的前 2 n 2n 2n项,然后用BM算法求出其递推式,设 p i p_i pi的生成函数为 P ( x ) P(x) P(x),那么要求的就是 P ′ ( 1 ) P'(1) P(1)
h ( x ) h(x) h(x) p i p_i pi的递推式生成函数,那么 P ( x ) P(x) P(x)可以表示成 A ( x ) h ( x ) − 1 \frac{A(x)}{h(x)-1} h(x)1A(x)的形式,就做完了。

代码

#include
#define pb push_back

typedef long long LL;

const int MOD=998244353;
const int N=6005;

int n,a[N],b[N],c[N],deg[N],cnt,last[N],m,f[2][N];
std::vector<int> h;
struct edge{int to,next;}e[N*6];

int ksm(int x,int y)
{
	int ans=1;
	while (y)
	{
		if (y&1) ans=(LL)ans*x%MOD;
		x=(LL)x*x%MOD;y>>=1;
	}
	return ans;
}

namespace BM
{
	int delta[N],fail[N];
	std::vector<int> r[N],t;
	std::vector<int> work(int n,int *a)
	{
		int cnt=0,mx=0;
		for (int i=1;i<=n;i++)
		{
			int w=a[i];
			for (int j=0;j<r[cnt].size();j++) (w+=MOD-(LL)r[cnt][j]*a[i-j-1]%MOD)%=MOD;
			if (!w) continue;
			delta[cnt]=w;
			fail[cnt]=i;
			if (!cnt) {r[++cnt].clear();r[cnt].resize(i);continue;}
			int mul=(LL)delta[cnt]*ksm(delta[mx],MOD-2)%MOD;
			t.clear();t.resize(i-fail[mx]-1);t.pb(mul);
			for (int j=0;j<r[mx].size();j++) t.pb(MOD-(LL)r[mx][j]*mul%MOD);
			if (t.size()<r[cnt].size()) t.resize(r[cnt].size());
			for (int j=0;j<r[cnt].size();j++) (t[j]+=r[cnt][j])%=MOD;
			if (r[cnt].size()-i<r[mx].size()-fail[mx]) mx=cnt;
			r[++cnt]=t;
		}
		return r[cnt];
	}
}

void addedge(int u,int v)
{
	e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
	e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

int main()
{
	scanf("%d",&n);
	for (int i=1,x,y;i<=n;i++) scanf("%d%d",&x,&y);
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		addedge(x,y);
		deg[x]++;deg[y]++;
	}
	for (int i=1;i<=n;i++) deg[i]=ksm(deg[i],MOD-2);
	f[0][1]=1;
	int now=0;
	for (int i=1;i<=n*2;i++)
	{
		for (int j=1;j<=n;j++) f[now][j]=(LL)f[now][j]*deg[j]%MOD;
		now^=1;
		for (int j=1;j<=n;j++)
		{
			f[now][j]=0;
			for (int k=last[j];k;k=e[k].next)
				if (e[k].to!=n) (f[now][j]+=(LL)f[now^1][e[k].to])%=MOD;
		}
		a[i]=f[now][n];
	}
	h=BM::work(n*2,a);
	int l=h.size();
	for (int i=1;i<=l;i++) c[i]=h[i-1];
	for (int i=1;i<=l;i++)
		for (int j=1;j<=l;j++)
			if (i+j<=l) (b[i+j]+=(LL)c[i]*a[j]%MOD)%=MOD;
	for (int i=1;i<=l;i++) (b[i]+=MOD-a[i])%=MOD;
	int c1=0,c2=0,b1=0,b2=0;
	for (int i=1;i<=l;i++)
	{
		(c1+=c[i])%=MOD;(c2+=(LL)c[i]*i%MOD)%=MOD;
		(b1+=b[i])%=MOD;(b2+=(LL)b[i]*i%MOD)%=MOD;
	}
	int ans=(LL)((LL)b2*(c1-1)-(LL)c2*b1)%MOD*ksm((LL)(c1-1)*(c1-1)%MOD,MOD-2)%MOD;
	ans+=ans<0?MOD:0;
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(生成函数)