【题目描述】
地面上出现了一个n*m的矩阵,矩阵的每个格子上有不等量(0~k)的魔液。
小A和小B各有一个魔瓶,他们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束。开始时小A用魔瓶吸收地面上的魔液,下一步由小B吸收,如此交替下去,并且要求最后一步必须由小B吸收。魔瓶只有k的容量,也就是说,如果装了k+1那么魔瓶会被清空成零,如果装了k+2就只剩下1,依次类推。
现在询问要想使他们俩的魔瓶中魔液一样多有多少种方法。
【输入描述】
第一行,三个空格隔开的整数n、m、k;
接下来n行m列,表示矩阵每一个格子的魔液量。同一行的数字用空格隔开。
【输出描述】
输出一个整数,表示方法数。由于可能很大,输出对1000000007取余后的结果。
【输入样例】
2 2 3
1 1
1 1
【输出样例】
4
【数据范围及提示】
样例的四种方案是:(1,1) --> (1,2),(1,1) --> (2,1),(1,2) --> (2,2),(2,1) --> (2,2)。
对于20%的数据,n,m <= 10,k <= 2;
对于50%的数据,n,m <= 100,k <= 5;
对于100%的数据,n,m <= 800,1 <= k <= 15。
源代码: #include<cstdio> #define INF 1000000007 int i[801][801],f[801][801][16][2]; //可得好生看着点数据范围。 int n,m,k; int main() { scanf("%d%d%d",&n,&m,&k); for (int a=0;a<n;a++) for (int b=0;b<m;b++) //注意读入范围。 { scanf("%d",&i[a][b]); f[a][b][i[a][b]][0]=1; //初始化赋值,可能从任意一个格子出发。 } k++; //改变一下值,瓶子方便清零。 for (int a=0;a<n;a++) for (int b=0;b<m;b++) for (int c=0;c<k;c++) //再循环k就和0重复啦。 { int &Ans1=f[a][b][c][0]; //偷懒的好办法。 int &Ans2=f[a][b][c][1]; if (a) //范围而已,同理于下。 { Ans1=(Ans1+f[a-1][b][(c-i[a][b]+k)%k][1])%INF; Ans2=(Ans2+f[a-1][b][(c+i[a][b])%k][0])%INF; } if (b) { Ans1=(Ans1+f[a][b-1][(c-i[a][b]+k)%k][1])%INF; Ans2=(Ans2+f[a][b-1][(c+i[a][b])%k][0])%INF; } } int Ans=0; for (int a=0;a<n;a++) for (int b=0;b<m;b++) Ans=(Ans+f[a][b][0][1])%INF; //符合条件的方案数之和。 printf("%d",Ans); return 0; } /* 第一眼就想**DP,然而并没有多少时间留给我。 类似于棋盘DP,设f[i][j][k][l]为走到(i,j),小A与小B相差为k时的方案数,l=0表示小A最后走,l=1表示小B最后走。 */