大逃离

【题目描述】

地面上出现了一个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最后走。
*/

 

posted @ 2016-08-27 15:38  前前前世。  阅读(206)  评论(0编辑  收藏  举报