[UER #6] 逃跑

一、题目

点此看题

二、解法

以前的博客不是很好,现在另起炉灶重写一波。

首先我们知道 \(E(\overline x)=E(x^2)-E^2(x)\),这可以用期望的线性性简单推出。

可以先预处理 \(g(t,i,j)\),表示经过 \(t\) 的时间,我们走到 \((i,j)\) 的方案数,这个可以直接 \(O(n^3)\) 递推弄出来。对于 \(E(x)\) 我们考虑求单点的贡献,设 \(f(i)\) 表示经过 \(i\) 的时间第一次到达 \((a,b)\),对于所有 \((a,b)\) 的方案数求和:

\[f(i)=(w_1+w_2+w_3+w_4)^i-\sum_{j=0}^{i-1}f(j)\cdot g(i-j,0,0) \]

\(pw(i)=(w_1+w_2+w_3+w_4)^i\),那么 \(E(x)\) 就可以很容易地求出了:

\[E(x)=\sum_{i=0}^n f(i)\cdot pw(n-i) \]

对于 \(E(x^2)\) 我们考虑求出点对之间的贡献,设 \(h(i,x,y)\) 表示在时间 \(i\) 内,我们经过 \((a,b)\),第一次到达 \((a+x,b+y)\) 的方案数。转移考虑容斥原理,总的方案数是先第一次走到 \((a,b)\),然后任意走到 \((a+x,b+y)\)

如果去重需要减去两项:第一项是经过 \((a+x,b+y)\) 走到 \((a,b)\),然后再走到 \((a+x,b+y)\);第二项是完成目标之后还在原地打转,也就是事实上不需要这么多时间,那么总转移方程:

\[h(i,x,y)=\sum_{j=0}^{i-1}f(j)\cdot g(i-j,x,y)-h(j,-x,-y)\cdot g(i-j,x,y)-h(j,x,y)\cdot g(i-j,0,0) \]

因为我们是按经过顺序计算的贡献,所以如果对他求和求出来的是 \(E({x\choose 2})\),那么 \(E(x^2)\) 可以表示成:

\[E(x^2)=E(x)+2\sum h(i,x,y)\cdot pw(n-i) \]

三、总结

本题的转化链十分巧妙,经过的点数可以在第一次经过的时候算贡献。而第一次经过的模型是经典问题,我们常常正难则反,减去的东西就规约到了子问题。

状态定义也值得学习,本题是把一个等价类定义到了状态中。这是因为它们的总方案易于计算,而容斥的方式是本质相同的,最后的答案也只需要求和,所以可以压缩在一起,寻找等价类的关键就是找他们的共同点。

#include <cstdio>
const int M = 205;
const int N = 105;
const int MOD = 998244353;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,w1,w2,w3,w4,d1,d2;
int pw[M],f[M],g[M][M][M],h[M][M][M];
void add(int &x,int y) {x=((x+y)%MOD+MOD)%MOD;}
signed main()
{
	n=read();w1=read();
	w2=read();w3=read();w4=read();
	g[0][0+N][0+N]=pw[0]=1;
	for(int i=1;i<=n;i++)
		pw[i]=pw[i-1]*(w1+w2+w3+w4)%MOD;
	for(int t=1;t<=n;t++)
	for(int i=-t;i<=t;i++)
	for(int j=-t;j<=t;j++)
	{
		int tmp=g[t-1][i+N][j+N];
		add(g[t][i+1+N][j+N],tmp*w1);
		add(g[t][i-1+N][j+N],tmp*w2);
		add(g[t][i+N][j+1+N],tmp*w3);
		add(g[t][i+N][j-1+N],tmp*w4);
	}
	for(int i=0;i<=n;i++)
	{
		f[i]=pw[i];
		for(int j=0;j<i;j++)
			add(f[i],-f[j]*g[i-j][0+N][0+N]);
		add(d1,f[i]*pw[n-i]);
	}
	for(int i=1;i<=n;i++)
	for(int x=-i;x<=i;x++)
	for(int y=-i;y<=i;y++)
	{
		if(x==0 && y==0) continue;
		int &r=h[i][x+N][y+N];
		for(int j=0;j<i;j++)
		{
			add(r,f[j]*g[i-j][x+N][y+N]);
			add(r,-h[j][-x+N][-y+N]*g[i-j][x+N][y+N]);
			add(r,-h[j][x+N][y+N]*g[i-j][0+N][0+N]);
		}
		add(d2,r*pw[n-i]);
	}
	add(d2,d2);add(d2,d1);
	printf("%lld\n",((d2*pw[n]-d1*d1)%MOD+MOD)%MOD);
}
posted @ 2021-11-18 08:18  C202044zxy  阅读(406)  评论(3编辑  收藏  举报