zoukankan      html  css  js  c++  java
  • P1373 小a和uim之大逃离(DP)

    (点击此处查看原题)

    题意

    中文题,题意看题面吧。

    解题思路

    注意到我们只能向右和下移动,由此想到开二维的dp数组dp[i][j],代表当前所在位置

    我们需要让两人取数的差值为0,由于起点和走法的不同,在同一位置上差值可能不同,为此,dp数组再多开一个维度:dp[i][j][p],表示取完位置[i,j]的数后,二者的差值为p

    我最开始想到的就是三维度的dp数组,不过写完后发现方程转移就不太灵活了,主要原因在于不知道当前位置是谁进行取数,因为这将影响p的转移

    为了让p可以准确的转移,我们为dp数组再多开一个维度:dp[i][j][p][type] 表示在位置[i,j]处由type取数,使得两者的差值为p(type == 0 表示小a取数,type == 1 表示uim取数)

    得到了可以转移的dp数组后,此时的状态转移方程就显然易见了:

    /***********************/

    k = k + 1; //差距为k+1的时候会抵消,此时为了节省代码量,先处理一下

    状态转移方程
    dp[i][j][p][0] += dp[i-1][j][(p - val[i][j] + k)%k][1];
    dp[i][j][p][0] += dp[i][j-1][(p - val[i][j] + k)%k][1];
    dp[i][j][p][1] += dp[i-1][j][(p + val[i][j])%k][0];
    dp[i][j][p][1] += dp[i][j-1][(p + val[i][j])%k][0];

    预处理
    dp[i][j][val[i][j]][0] = 1;

    计算出以每个点为终点得到的最大方案数之和
    sum += dp[i][j][0][1]; (1 <= i <= n , 1 <= j <= m)

    代码区

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 1e9 + 7;
    const int mod = 1e9 + 7;
    const int Max = 1e6 + 10;
    
    int n, m, k;
    int val[805][805];
    int dp[805][805][20][2];        //记录从(i,j)出发,这一位置的数由(0:小a,1:uim)取走情况下,两者之差为p的方案数
    /*
     * k = k + 1;                    //差距为k+1的时候会抵消,此时为了节省代码量,先处理一下
     * dp[i][j][p][0] += dp[i-1][j][(p - val[i][j] + k)%k][1];
     * dp[i][j][p][0] += dp[i][j-1][(p - val[i][j] + k)%k][1];
     * dp[i][j][p][1] += dp[i-1][j][(p + val[i][j])%k][0];
     * dp[i][j][p][1] += dp[i][j-1][(p + val[i][j])%k][0];
     *
     * 预处理
     * dp[i][j][val[i][j]][0] = 1;
     *
     * 计算出以每个点为终点得到的最大方案数之和
     * sum += dp[i][j][0][1];    (1 <= i <= n , 1 <= j <= m)
     */
    
    int main()
    {
    #ifdef LOCAL
    //    freopen("input.txt", "r", stdin);
    //    freopen("output.txt", "w", stdout);
    #endif
        scanf("%d%d%d", &n, &m, &k);
        k++;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", val[i] + j), dp[i][j][val[i][j] % k][0] = 1;
    
        int sum = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                for (int p = 0; p <= k; p++)
                {
                    dp[i][j][p][0] = (dp[i][j][p][0] + dp[i - 1][j][(p - val[i][j] + k) % k][1]) % mod;
                    dp[i][j][p][0] = (dp[i][j][p][0] + dp[i][j - 1][(p - val[i][j] + k) % k][1]) % mod;
    
                    dp[i][j][p][1] = (dp[i][j][p][1] + dp[i - 1][j][(p + val[i][j]) % k][0]) % mod;
                    dp[i][j][p][1] = (dp[i][j][p][1] + dp[i][j - 1][(p + val[i][j]) % k][0]) % mod;
                }
                sum = (sum + dp[i][j][0][1]) % mod;
            }
        }
        printf("%d
    ", sum);
        return 0;
    }
    View Code
  • 相关阅读:
    祈澈菇凉的高端知识资源分享星球开通
    使用mpvue开发小程序教程(五)
    使用mpvue开发小程序教程(四)
    使用mpvue开发小程序教程(三)
    使用mpvue开发小程序教程(二)
    使用mpvue开发小程序教程(一)
    手把手教你用vue-cli构建一个简单的路由应用
    wangEditor
    从列表中或数组中随机抽取固定数量的元素组成新的数组或列表
    js学习总结----核心解读
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11505096.html
Copyright © 2011-2022 走看看