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;
}
posted @ 2018-10-31 13:45  Garen-Wang  阅读(96)  评论(0编辑  收藏  举报