//My AC Code:
#include <bits/stdc++.h>
using namespace std;
const int mo = 1e9+7;
int n,m,k;
int nm[805][805];
int dp[805][805][20][2],ans;
/*
他们 可以从 n*m的矩阵的任何一个位置 开始 一起走!
dp数组 表示 第a行b列 的时候,小a和小uim魔瓶中的魔液量差 为 c ,最后一个位置 0表示 小a 先吸收,1表示小uim先吸收
*/
/*
一直以为 f[i][j][p][1]+=f[i-1][j][p+a[i][j]][0]与 f[i][j][p][0]+=f[i][j-1][p-a[i][j]][1] 顺序不能颠倒 验证后可以颠倒
*/
int main(){
/*
精髓
f[i][j][p][q]表示他们走到(i,j),
且两人魔瓶内魔液量的差为p时的方法数。
q=0表示最后一步是小a走的,q=1表示最后一步是uim走的。
题目中说魔瓶的容量为k,实际上就是动归时p需要对k+1取余数,
即p只有0~k,k+1种可能。
答案为所有f[i][j][0][1]的和。
*/
scanf("%d%d%d",&n,&m,&k);
k++;//因为 % 要为 k+1 即 魔液量不能超过k+1
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&nm[i][j]);
dp[i][j][nm[i][j]][0]=1;
}
/*
对 dp数组进行初始化
一开始 第i行j列 小a先手,也就是说 小uim当前是魔瓶里面没有魔液的 即 差值为 0-nm[i][j] = nm[i][j]
所以 i行j列差值为nm[i][j]且小a先手(最后一个吸取魔液体)的方案数为1
*/
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int qwq=0;qwq<=k-1;qwq++){
dp[i][j][qwq][0]+=dp[i-1][j][(qwq-nm[i][j]+k)%k][1];
dp[i][j][qwq][0]%=mo;
dp[i][j][qwq][0]+=dp[i][j-1][(qwq-nm[i][j]+k)%k][1];
dp[i][j][qwq][0]%=mo;
dp[i][j][qwq][1]+=dp[i-1][j][(qwq+nm[i][j])%k][0];
dp[i][j][qwq][1]%=mo;
dp[i][j][qwq][1]+=dp[i][j-1][(qwq+nm[i][j])%k][0];
dp[i][j][qwq][1]%=mo;
/*
题目说 可以往右或者下走,也就是说要向左向上 往前推 也就是 1-n,1-m,0-k地推
设 小a的魔瓶 魔液量为a 小uim的魔瓶魔液量为b 则 他们的魔液量差值为 qwq = a-b
如果dp推到 dp[i][j][qwq][0] ,则状态是从 上一个 小uim 操作 得来的
即 上一个 小uim的操作 有可能从上面来 也可能从左边来
上一个 小uim操作,差值为 a-(nm[i][j]) - b = a-b-nm[i][j] = qwq-nm[i][j] (b还是 当前dp的那个小uim的魔瓶魔液量 )
因为qwq-nm[i][j] 可能是负数 所以要+k (k=k+1)
so dp[i][j][qwq][0]+=dp[i-1][j][(qwq-nm[i][j]+k)%k][1]; dp[i][j][qwq][0]+=dp[i][j-1][(qwq-nm[i][j]+k)%k][1];
同理
如果dp推到 dp[i][j][qwq][1],则上一个状态是由小a 操作 得来的
即 上一个 小a的操作 有可能是从上面来的 也有可能是从左边来的
上一个 小a的操作,两人的魔瓶魔液量 差值为 a-(b-nm[i][j])=a-b+nm[i][j]=qwq+nm[i][j] (a 还是 当前dp的那个小a的魔瓶魔液量)
因为 qwq+nm[i][j] 有可能会超过k (k=k+1) 所以 要 %k
so dp[i][j][qwq][1]+=dp[i-1][j][(qwq+nm[i][j])%k][0];dp[i][j][qwq][1]+=dp[i][j-1][(qwq+nm[i][j])%k][0];
*/
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans+=(dp[i][j][0][1]),ans%=mo;
printf("%d",ans);
return 0;
}
P1373 小a和uim之大逃离
2019-05-10