题目背景
小a和uim来到雨林中探险。突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声。刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发、青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”。小a和他的小伙伴都惊呆了!
题目描述
瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液。怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束。开始时小a用魔瓶吸收地面上的魔液,下一步由uim吸收,如此交替下去,并且要求最后一步必须由uim吸收。魔瓶只有k的容量,也就是说,如果装了k+1那么魔瓶会被清空成零,如果装了k+2就只剩下1,依次类推。怪物还说道,最后谁的魔瓶装的魔液多,谁就能活下来。小a和uim感情深厚,情同手足,怎能忍心让小伙伴离自己而去呢?沉默片刻,小a灵机一动,如果他俩的魔瓶中魔液一样多,不就都能活下来了吗?小a和他的小伙伴都笑呆了!
现在他想知道他们都能活下来有多少种方法。
输入输出格式
输入格式:
第一行,三个空格隔开的整数n,m,k
接下来n行,m列,表示矩阵每一个的魔液量。同一行的数字用空格隔开。
输出格式:
一个整数,表示方法数。由于可能很大,输出对1 000 000 007取余后的结果。
输入样例#1:
2 2 3
1 1
1 1
输出样例#1:
4
思路&题解:
最开始看到这道题的时候我是想将两个人每个人各走一次看作一个单位来做DP,但是这样的话状态转移方程写不出来,所以只能每人分开走一次来计算,所以我就确定了最初的状态:f[i][j][0/1]表示当走到Cij的时候最后一个走的人是0或1的时候当前瓶子中魔液的差值。但是,当我想状态转移方程的时候发现还是不好想,于是就无奈地看了题解。题解提供的思路是把这个题当作背包来想,开一个四维数组f[i][j][h][0/1]来记录能走到Cij,并且这个时候两人魔液的差值为h,最后走的人是0/1的状态的方案数量。状态转移方程也就不难得出了,具体看代码吧。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int N=805,mod=1000000007; 7 int n,m,k,matr[N][N],f[N][N][20][2];//0代表a最后走,1代表u最后走 8 void Init() 9 { 10 memset(f,0,sizeof(f)); 11 int i,j; 12 scanf("%d%d%d",&n,&m,&k); 13 for(i=1;i<=n;i++) 14 { 15 for(j=1;j<=m;j++) 16 { 17 scanf("%d",&matr[i][j]); 18 f[i][j][matr[i][j]%(k+1)][0]=1; 19 } 20 } 21 } 22 void work() 23 { 24 int i,j,h,ans=0; 25 for(i=1;i<=n;i++) 26 { 27 for(j=1;j<=m;j++) 28 { 29 for(h=0;h<=k;h++) 30 { 31 int n1=(h+matr[i][j])%(k+1),n2=((h-matr[i][j])%(k+1)+(k+1))%(k+1); 32 if(i>1) 33 { 34 f[i][j][h][0]=((f[i-1][j][n2][1]+f[i][j][h][0])%mod+mod)%mod; 35 f[i][j][h][1]=((f[i-1][j][n1][0]+f[i][j][h][1])%mod+mod)%mod; 36 } 37 if(j>1) 38 { 39 f[i][j][h][0]=((f[i][j-1][n2][1]+f[i][j][h][0])%mod+mod)%mod; 40 f[i][j][h][1]=((f[i][j-1][n1][0]+f[i][j][h][1])%mod+mod)%mod; 41 } 42 if(h==0) 43 { 44 ans+=f[i][j][h][1]; 45 ans%=mod; 46 } 47 } 48 } 49 } 50 printf("%d",ans); 51 } 52 int main() 53 { 54 Init(); 55 work(); 56 return 0; 57 }