非常痛快的一道DP。
看到机房的同学在写,所以就跟着拿来练练手。
结果一开始理解错题意......还以为两个人可以从不同的格子出发,导致我丧心病狂地开了一个805×805×805×805的四维数组
不MLE才怪......
读懂题之后,发现只有一个坐标状态需要记录,豁然开朗;
本来打算开成 $ f[805][805][16][16][2] $ 的数组,表示坐标,小a的容量,uim的容量,当前由谁取
试了一下发现还是MLE
又想了一会发现可以将两维压缩为一位,表示两人容量的差值。
于是,就成功地表示出了状态。
$ f[x][y][h][0/1] $ 表示:走到的坐标为(x,y),两人容量差为h,当前应由小a(0)或uim(1)取魔液 该状态下的方案数。
然后考虑初始化:
因为从小a开始走(这一点我自己做的时候居然没看到),所以只需要把所有的 $ f[x][y][a[x][y]][1] $ 赋值为1(方案数为1)即可。
然后就是状态转移方程,主要是处理两人容量差:
$ f[x][y][h][0]+=f[x-1][y][(h-a[i][j]+k)%k][1] $
$ f[x][y][h][0]+=f[x][y-1][(h-a[i][j]+k)%k][1] $
$ f[x][y][h][1]+=f[x-1][y][(h+a[i][j])%k][0] $
$ f[x][y][h][1]+=f[x][y-1][(h+a[i][j])%k][0] $
解释一下: $ h-a[i][j] $ 是转移之前的h值,+k再%k是为了防止负数。
下面的h+a[i][j]同理,只不过不需要+k再%k防负数。
其实写成 $ (h+a[i][j]+k)%k $ 也不会错,亲测。
然后,遍历所有的差值为0的情况的方案数,加起来再模上模数,就是答案了。
LL ans=0;
for(int i(1);i<=n;i++){
for(int j(1);j<=m;j++){
ans=(ans+f[i][j][0][1])%mo;
}
}