题目描述:传送门
一看这题首先想到设
d(i,j,k1,k2,0)
表示在小a刚吸完i,j这个位置的魔液,小a和uim的魔瓶的魔液量分别为k1,k2时的方案数,
d(i,j,k1,k2,1)
表示在uim刚吸完……的方案数。
但是这样明显会爆内存…于是我就一直卡着了。后来看到讨论区有差这个字,才想到把状态减少到
d(i,j,k,0)
和
d(i,j,k,1)
其中k为 小a的魔瓶量与uim的魔瓶量之差.
另外我用的是顺推,感觉更好想。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int mo=1e9+7;
int n,m,k,d[800][800][16][2],a[800][800];
int main(){
scanf("%d%d%d",&n,&m,&k);
memset(d,0,sizeof(d));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
scanf("%d",&a[i][j]);
d[i][j][a[i][j]][0]=1;
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
for(int u=0;u<=k;u++){
int k1;
if(i+1<n){
k1=u+a[i+1][j];
if(k1>k) k1-=(k+1);
d[i+1][j][k1][0]=(d[i+1][j][k1][0]+d[i][j][u][1])%mo;
k1=u-a[i+1][j];
if(k1<0) k1+=(k+1);
d[i+1][j][k1][1]=(d[i+1][j][k1][1]+d[i][j][u][0])%mo;
}
if(j+1<m){
k1=u+a[i][j+1];
if(k1>k) k1-=(k+1);
d[i][j+1][k1][0]=(d[i][j+1][k1][0]+d[i][j][u][1])%mo;
k1=u-a[i][j+1];
if(k1<0) k1+=(k+1);
d[i][j+1][k1][1]=(d[i][j+1][k1][1]+d[i][j][u][0])%mo;
}
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
ans=(ans+d[i][j][0][1])%mo;
cout<<ans<<endl;
return 0;
}