[UER#6 C]逃跑

做法

要求的是方差,实际就是求所有情况下经过不同位置的个数和以及经过不同位置的平方和,设为 d d d2
一共有四种方向向量,任意走法对应一种向量序列。
先预处理 W(i,x,y) W ( i , x , y ) 表示长度为 i i ,和为(x,y)的向量序列有多少种。
如何求 d d ,当然是很简单的。
每个坐标显然可以独立统计贡献,我们希望在每个坐标第一次被走到时统计到它。
我们设g[i]表示长度为 i i ,且不存在1ji满足前 j j 个向量前缀和为(0,0)
以后这种类似的情况简单称为“不存在前缀 (0,0) ( 0 , 0 ) ”。
显然可以容斥:
g[i]=(w1+w2+w3+w4)iij=1W(j,0,0)g[ij] g [ i ] = ( w 1 + w 2 + w 3 + w 4 ) i − ∑ j = 1 i W ( j , 0 , 0 ) ∗ g [ i − j ]
那么就有
d=ni=0(x,y)W(i,x,y)g[ni] d = ∑ i = 0 n ∑ ( x , y ) W ( i , x , y ) ∗ g [ n − i ]
在时刻 i i 我们走到了(x,y),之后再也没有再走到过。
为了简单计算,我们更改 d2 d 2 的含义,对于一种情况,对于两个不同的位置(有序)如果都到达过,给 d2 d 2 贡献 1 1 。那么原本的d2等于新的 d2 d 2 2 2 加上d
类似的我们设出 R(i,x,y) R ( i , x , y ) 表示长度为 i i ,和为(x,y),不存在前缀 (0,0) ( 0 , 0 )
R R 的计算也可以容斥:
R(i,x,y)=W(i,x,y)j=1iW(j,0,0)R(ij,x,y)
然后我们设 S(i,x,y) S ( i , x , y ) 表示长度为 i i ,和为(0,0),且存在前缀 (x,y) ( x , y )
那么显然
S(i,x,y)=ij=1W(j,x,y)R(ij,x,y) S ( i , x , y ) = ∑ j = 1 i W ( j , x , y ) ∗ R ( i − j , − x , − y )
有了这几个作辅助,我们可以设 F(i,x,y) F ( i , x , y ) 表示长度为 i i 的所有情况,前j个向量的和 (a,b) ( a , b ) 为第一次到达,然后接下来 ij i − j 个向量的和为 (x,y) ( x , y ) ,且在位置 i i 时,(a+x,b+y)第一次到达,这样的两个不同位置总数(因此 xy x y 不为 0 0 )。
可能有点绕。
考虑怎么得到它呢?
F(i,x,y)+=j=1ig[j]W(ij,x,y)
这个是 (a,b) ( a , b ) 是第一次到达的总方案数。
考虑不合法的情况,即 (a,b) ( a , b ) 到达 (a+x,b+y) ( a + x , b + y ) 后,这个 (a+x,b+y) ( a + x , b + y ) 已经不是第一次到达了,它可能在第一次到达 (a,b) ( a , b ) 前第一次到达,也可能在第一次到达 (a,b) ( a , b ) 后第一次到达。
F(i,x,y)=ij=1g[j]S(ij,x,y) F ( i , x , y ) − = ∑ j = 1 i g [ j ] ∗ S ( i − j , − x , − y )
如果在第一次到达 (a,b) ( a , b ) 之前就到达了 (a+x,b+y) ( a + x , b + y ) ,考虑去掉这种方案,那么相当于第一次到达 (a+x,b+y) ( a + x , b + y ) 后又走了回来,而且这途中要经过 (a,b) ( a , b ) 。这样一定包含了所有第一次到达 (a,b) ( a , b ) 之前就到达了 (a+x,b+y) ( a + x , b + y ) 的方案,但是并不止。我们中途去遍历了 (a,b) ( a , b ) ,但是并不一定中途遍历时这个 (a,b) ( a , b ) 才第一次经过。因此我们还会减掉第一次到达 (a,b) ( a , b ) 后,再第一次到达 (a+x,b+y) ( a + x , b + y ) ,最后在时刻 i i 重新回到(a+x,b+y),这中途还重新回过 (a,b) ( a , b )
F(i,x,y)=ij=1F(j,x,y)(W(ij,0,0)S(ij,x,y)) F ( i , x , y ) − = ∑ j = 1 i F ( j , x , y ) ∗ ( W ( i − j , 0 , 0 ) − S ( i − j , − x , − y ) )
我们考虑第一次到达 (a+x,b+y) ( a + x , b + y ) 是在第一次到达 (a,b) ( a , b ) 后的不合法方案,注意到上一条式子里我们减掉了第一次到达 (a+x,b+y) ( a + x , b + y ) 到时刻 i i 间重新回过(a,b)的方案,这里为了不减重要减掉这种方案(即 S(ij,x,y) S ( i − j , − x , − y ) )。
那么在得到了 F F 之后,我们很简单就能统计d2
d2=ni=0(a,b)(x,y)F(i,a,b)W(ni,x,y) d 2 = ∑ i = 0 n ∑ ( a , b ) ∑ ( x , y ) F ( i , a , b ) ∗ W ( n − i , x , y )
至此,本题解决。时间复杂度 O(n4) O ( n 4 )

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=220+10,mo=998244353;
int w[5],dx[5]={0,0,0,1,-1},dy[5]={0,-1,1,0,0};
int p1[maxn][maxn][maxn],p2[maxn][maxn][maxn],p3[maxn][maxn][maxn],p4[maxn][maxn][maxn];
int g[maxn];
int i,j,k,l,r,s,t,n,m,x,y,ans,all,d,d2;
int &W(int n,int x,int y){ return p1[x+105][y+105][n]; }
int &F(int n,int x,int y){ return p2[x+105][y+105][n]; }
int &S(int n,int x,int y){ return p3[x+105][y+105][n]; }
int &R(int n,int x,int y){ return p4[x+105][y+105][n]; }
int abs(int x){
    return x<0?-x:x;
}
int main(){
    scanf("%d",&n);
    fo(i,1,4) scanf("%d",&w[i]);
    W(0,0,0)=1;
    fo(i,1,n)
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i)
                    fo(k,1,4)
                        (W(i,x,y)+=(ll)w[k]*W(i-1,x+dx[k],y+dy[k])%mo)%=mo;
    g[0]=1;
    all=w[1]+w[2]+w[3]+w[4];
    t=1;
    fo(i,1,n){
        t=(ll)t*all%mo;
        g[i]=t;
        fo(j,1,i) (g[i]-=(ll)W(j,0,0)*g[i-j]%mo)%=mo;
    }
    fo(i,1,n)
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i){
                    R(i,x,y)=W(i,x,y);
                    fo(j,1,i-abs(x)-abs(y))
                        (R(i,x,y)-=(ll)W(j,0,0)*R(i-j,x,y)%mo)%=mo;
                }
    fo(i,1,n)
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i){
                    fo(j,max(abs(x)+abs(y),1),i-abs(x)-abs(y))
                        (S(i,x,y)+=(ll)W(j,x,y)*R(i-j,-x,-y)%mo)%=mo;
                }
    fo(i,1,n)
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i){
                    if (!x&&!y) continue;
                    fo(j,max(abs(x)+abs(y),1),i)
                        (F(i,x,y)+=(ll)(W(j,x,y)-S(j,x,y))*g[i-j]%mo)%=mo;
                    fo(j,1,i)
                        (F(i,x,y)-=(ll)(W(j,0,0)-S(j,x,y))*F(i-j,x,y)%mo)%=mo;
                }
    fo(i,0,n)
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i) (d+=(ll)W(i,x,y)*g[n-i]%mo)%=mo;
    fo(i,0,n){
        t=0;
        fo(x,-n,n)
            fo(y,-n,n)
                if ((x||y)&&abs(x)+abs(y)<=n-i) (t+=F(n-i,x,y))%=mo;
        fo(x,-n,n)
            fo(y,-n,n)
                if (abs(x)+abs(y)<=i) (d2+=(ll)t*W(i,x,y)%mo)%=mo;
    }
    d2=((ll)d2*2%mo+d)%mo;
    t=1;
    fo(i,1,n) t=(ll)t*all%mo;
    ans=((ll)d2*t%mo-(ll)d*d%mo)%mo;
    (ans+=mo)%=mo;
    printf("%d\n",ans);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值