P1373 小a和uim之大逃离
古老的dp好题
50分的做法是肯定能想出来的。设dp[i][j][k][l][2]
表示当前走到\(i\)行\(j\)列,两人瓶子的容量分别为\(k\)和\(l\),现在这一步是由谁走的。
但是显然数组开不下。转移也挺麻烦的。
满分做法:
直接把两人瓶子的容量合成一维就可以了。合并为两人容量的差值。
转移有一个问题:他们的差值可能是负的啊!
直接像求逆元那样,在\(k+1\)这个膜里面找到一个等效的,存进去即可。
因为每一步只能走右或者走下,所以会从\((i-1,j)\)和\((i,j-1)\)转移过来。
随便钦定那个差值是谁跟谁的作差,然后不要弄混,就可以成功地转移了。
代码:
#include<cstdio>
const int maxn = 801, maxk = 16;
const int MOD = 1000000007;
int dp[maxn][maxn][maxk][2];
int a[maxn][maxn];
int n, m, K;
int main()
{
scanf("%d%d%d", &n, &m, &K);
K++;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
dp[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 < K; k++)
{
if(j - 1 >= 1)
{
dp[i][j][k][0] = (dp[i][j][k][0] + dp[i][j - 1][(k - a[i][j] + K) % K][1]) % MOD;
dp[i][j][k][1] = (dp[i][j][k][1] + dp[i][j - 1][(k + a[i][j]) % K][0]) % MOD;
}
if(i - 1 >= 1)
{
dp[i][j][k][0] = (dp[i][j][k][0] + dp[i - 1][j][(k - a[i][j] + K) % K][1]) % MOD;
dp[i][j][k][1] = (dp[i][j][k][1] + dp[i - 1][j][(k + a[i][j]) % K][0]) % MOD;
}
}
}
}
long long ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
ans = (ans + dp[i][j][0][1]) % MOD;
}
}
printf("%lld\n", ans);
return 0;
}