题目链接:https://www.luogu.org/problem/P1373
求方案数,然后数据范围800,感觉上就可以dp
因为是每个点都可以作为结束点,所以需要2维表示到了这个点2个人的差是k的方案数。
为了便于转移,要加一位0/1表示现在是小uim还是小a可以加水。
初始状态就是f[i][j][a[i][j]][0]=1(不难理解吧?)这样的话就不要一个一个枚举起点了。
#include <bits/stdc++.h>
using namespace std;
const int maxn=805;
const int mod=1000000007;
int n,m,p;
int a[maxn][maxn];
int f[maxn][maxn][20][2];//走到ij,相差p, 最后一步是谁
int main()
{
scanf("%d%d%d",&n,&m,&p);p+=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
a[i][j]%=p;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) f[i][j][a[i][j]][0]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k<p;k++)
{
int tmp=(k-a[i][j]+p)%p;
if(i>1) f[i][j][k][0]=(f[i][j][k][0]+f[i-1][j][tmp][1])%mod;
if(j>1) f[i][j][k][0]=(f[i][j][k][0]+f[i][j-1][tmp][1])%mod;
tmp=(k+a[i][j]+p)%p;
if(i>1) f[i][j][k][1]=(f[i][j][k][1]+f[i-1][j][tmp][0])%mod;
if(j>1) f[i][j][k][1]=(f[i][j][k][1]+f[i][j-1][tmp][0])%mod;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) ans=(ans+f[i][j][0][1])%mod;
printf("%d",ans);
return 0;
}