UOJ#211. 【UER #6】逃跑

谢谢栋栋教我这题qaq

因为完全按照他的方法做的所以题解和他的可能会长得很像qaq


先画一下柿子
a n s = E × a l l = a l l ∑ ( a i − a v e ) 2 = a l l ∑ ( a i 2 − 2 a i × a v e + a v e 2 ) ans=E×all=all\sum(a_i-ave)^2=all\sum(a_i^2-2a_i×ave+ave^2) ans=E×all=all(aiave)2=all(ai22ai×ave+ave2)
a v e = ∑ a i a l l ave=\dfrac{\sum ai}{all} ave=allai
a n s = a l l ∑ a i 2 − ( ∑ a i ) 2 ans=all\sum a_i^2-(\sum a_i)^2 ans=allai2(ai)2

我们设 w = w 1 + w 2 + w 3 + w 4 w=w1+w2+w3+w4 w=w1+w2+w3+w4 d = ∑ a i d=\sum a_i d=ai d 2 = ∑ a i 2 d_2=\sum a_i^2 d2=ai2
a n s = a l l × d 2 − d 2 ans=all×d_2-d^2 ans=all×d2d2,其中 a l l = w n all=w^n all=wn,考虑怎么求 d , d 2 d,d_2 d,d2


我们将四个方向看作四个向量,一开始在(0,0),走到(x,y)相当于向量和为(x,y)
以下将 “ 不存在一个 j ( j > 0 ) j(j>0) j(j>0)满足前 j j j个向量和为 ( x , y ) (x,y) (x,y) ” 简称为不存在前缀 ( x , y ) (x,y) (x,y),后缀同理

W [ i ] [ x ] [ y ] W[i][x][y] W[i][x][y]表示走了 i i i步,走到 ( x , y ) (x,y) (x,y)的方案数
g [ i ] g[i] g[i]表示走了 i i i步,不存在前缀 ( 0 , 0 ) (0,0) (0,0)的方案数(同时也是不存在后缀 ( 0 , 0 ) (0,0) (0,0)的方案数)
g [ i ] = w i − ∑ j W [ j ] [ 0 ] [ 0 ] × g [ i − j ] g[i]=w^i-\sum_jW[j][0][0]×g[i-j] g[i]=wijW[j][0][0]×g[ij]

那么 d d d就很容易计算了,我们分开考虑每个格子的贡献,有
d = ∑ i g [ i ] × w n − i d=\sum_ig[i]×w^{n-i} d=ig[i]×wni

对于 d 2 d_2 d2,我们考虑像管道取珠那样转化平方贡献的方法计算他

R [ i ] [ x ] [ y ] R[i][x][y] R[i][x][y]表示走了 i i i步,和为 ( x , y ) (x,y) (x,y),不存在前缀 ( 0 , 0 ) (0,0) (0,0)
R [ i ] [ x ] [ y ] = W [ i ] [ x ] [ y ] − ∑ j W [ j ] [ 0 ] [ 0 ] × R [ i − j ] [ x ] [ y ] R[i][x][y]=W[i][x][y]-\sum_jW[j][0][0]×R[i-j][x][y] R[i][x][y]=W[i][x][y]jW[j][0][0]×R[ij][x][y]

S [ i ] [ x ] [ y ] S[i][x][y] S[i][x][y]表示走了 i i i步,和为 ( 0 , 0 ) (0,0) (0,0),存在前缀 ( x , y ) (x,y) (x,y)
S [ i ] [ x ] [ y ] = ∑ j W [ j ] [ x ] [ y ] × R [ i − j ] [ − x ] [ − y ] S[i][x][y]=\sum_jW[j][x][y]×R[i-j][-x][-y] S[i][x][y]=jW[j][x][y]×R[ij][x][y]

F [ i ] [ x ] [ y ] F[i][x][y] F[i][x][y]表示
对于所有长度为 i i i的向量序列,其前 j ( j < i ) j(j<i) j(j<i)个向量和为 ( a , b ) (a,b) (a,b),后 i − j i-j ij个向量和为 ( x , y ) (x,y) (x,y)
且第 j j j步第一次到达 ( a , b ) (a,b) (a,b)(不存在后缀 ( 0 , 0 ) (0,0) (0,0)),第 i i i步第一次到达 ( a + x , b + y ) (a+x,b+y) (a+x,b+y)
这样的 j j j的个数之和

其实就是将一条路径覆盖的 a i a_i ai个格子,按照第一次到达的顺序排序后,从左到右取出每个格子和后面的所有格子匹配贡献到 a i 2 a_i^2 ai2里,最后要乘2算上倒序的匹配,再加上 a i a_i ai表示自己和自己匹配

F [ i ] [ x ] [ y ] F[i][x][y] F[i][x][y]的dp式分三部分

F [ i ] [ x ] [ y ] + = ∑ j g [ j ] × W [ i − j ] [ x ] [ y ] F[i][x][y]+=\sum_jg[j]×W[i-j][x][y] F[i][x][y]+=jg[j]×W[ij][x][y]
因为 g [ j ] g[j] g[j]也能表示不存在后缀 ( 0 , 0 ) (0,0) (0,0)即第一次到达某个点 ( a , b ) (a,b) (a,b),然后剩下 i − j i-j ij步和为 ( x , y ) (x,y) (x,y),所有合法方案他一定能算进去,考虑他会算到哪些不合法的方案
会算到不合法主要是因为我们不能保证第 i i i步时第一次到达 ( a + x , b + y ) (a+x,b+y) (a+x,b+y),他可能在第 j j j步前就到达过,或者在第 j j j步后第 i i i步前到达过

F [ i ] [ x ] [ y ] − = ∑ j g [ j ] × S [ i − j ] [ − x ] [ − y ] F[i][x][y]-=\sum_jg[j]×S[i-j][-x][-y] F[i][x][y]=jg[j]×S[ij][x][y]
这里减去的是第 j j j步前到达 ( a + x , b + y ) (a+x,b+y) (a+x,b+y)后走回 ( a , b ) (a,b) (a,b)再回到 ( a + x , b + y ) (a+x,b+y) (a+x,b+y)的方案,但他还会减去第一次到 ( a , b ) (a,b) (a,b)后到 ( a + x , b + y ) (a+x,b+y) (a+x,b+y)再绕回 ( a , b ) (a,b) (a,b)最后又回到 ( a + x , b + y ) (a+x,b+y) (a+x,b+y)的方案,因为我们第三部分会再减一次这种情况,所以我们要在第三部分把这些方案加回来(避免重复减同一种情况)

F [ i ] [ x ] [ y ] − = ∑ j F [ j ] [ x ] [ y ] × ( W [ i − j ] [ 0 ] [ 0 ] − S [ i − j ] [ − x ] [ − y ] ) F[i][x][y]-=\sum_jF[j][x][y]×(W[i-j][0][0]-S[i-j][-x][-y]) F[i][x][y]=jF[j][x][y]×(W[ij][0][0]S[ij][x][y])
这里的 S [ i − j ] [ − x ] [ − y ] S[i-j][-x][-y] S[ij][x][y]就是我们在第二部分多减的东西

然后 d 2 = ( ∑ i , x , y F [ i ] [ x ] [ y ] × w n − i ) × 2 + d d_2=(\sum_{i,x,y}F[i][x][y]×w^{n-i})×2+d d2=(i,x,yF[i][x][y]×wni)×2+d

然后这题就做完啦(撒花)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define W(i,x,y) W[x+base][y+base][i]
#define R(i,x,y) R[x+base][y+base][i]
#define S(i,x,y) S[x+base][y+base][i]
#define F(i,x,y) F[x+base][y+base][i]
using namespace std;

const int maxn = 210;
const int mod = 998244353;
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
const int base = 105;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
inline void dec(int &a,const int &b){a-=b;if(a<0)a+=mod;}

int n,w[4],pw[maxn];
int W[maxn][maxn][maxn],g[maxn],R[maxn][maxn][maxn],S[maxn][maxn][maxn],F[maxn][maxn][maxn];

int main()
{
	//freopen("tmp.in","r",stdin);
	//freopen("tmp.out","w",stdout);
	
	scanf("%d",&n);
	scanf("%d%d%d%d",&w[0],&w[2],&w[1],&w[3]);
	pw[0]=1,pw[1]=w[0]+w[1]+w[2]+w[3]; for(int i=2;i<=n;i++) pw[i]=(ll)pw[i-1]*pw[1]%mod;
	
	W(0,0,0)=1;
	for(int i=1;i<=n;i++)
	{
		for(int x=-i;x<=i;x++) for(int y=-i+abs(x);y<=i-abs(x);y++)
			for(int k=0;k<4;k++) add(W(i,x,y),(ll)W(i-1,x+dx[k],y+dy[k])*w[(k+2)&3]%mod);
	}
	for(int i=0;i<=n;i++)
	{
		g[i]=pw[i];
		for(int j=1;j<=i;j++) dec(g[i],(ll)W(j,0,0)*g[i-j]%mod);
	}
	for(int i=0;i<=n;i++)
	{
		for(int x=-i;x<=i;x++) for(int y=-i+abs(x);y<=i-abs(x);y++)
		{
			R(i,x,y)=W(i,x,y);
			for(int j=1;j<i;j++) dec(R(i,x,y),(ll)W(j,0,0)*R(i-j,x,y)%mod);
		}
	}
	for(int i=0;i<=n;i++)
	{
		for(int x=-i;x<=i;x++) for(int y=-i+abs(x);y<=i-abs(x);y++)
		{
			for(int j=1;j<i;j++) add(S(i,x,y),(ll)W(j,x,y)*R(i-j,-x,-y)%mod);
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int x=-i;x<=i;x++) for(int y=-i+abs(x);y<=i-abs(x);y++)
		{
			for(int j=0;j<i;j++) add(F(i,x,y),(ll)g[j]*W(i-j,x,y)%mod);
			for(int j=0;j<i;j++) dec(F(i,x,y),(ll)g[j]*S(i-j,-x,-y)%mod);
			for(int j=0;j<i;j++) dec(F(i,x,y),(ll)F(j,x,y)*((W(i-j,0,0)-S(i-j,-x,-y)+mod)%mod)%mod);
		}
	}
	int d=0,d2=0;
	for(int i=0;i<=n;i++) add(d,(ll)g[i]*pw[n-i]%mod);
	for(int i=0;i<=n;i++)
	{
		for(int x=-i;x<=i;x++) for(int y=-i+abs(x);y<=i-abs(x);y++) if(x||y)
			add(d2,(ll)F(i,x,y)*pw[n-i]%mod);
	}
	add(d2,d2);
	add(d2,d);
	int ans=(ll)d2*pw[n]%mod; dec(ans,(ll)d*d%mod);
	printf("%d\n",ans);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值