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\n", sum);
    return 0;
}

原文地址:https://www.cnblogs.com/winter-bamboo/p/11505096.html

时间: 2024-09-30 09:31:57

P1373 小a和uim之大逃离(DP)的相关文章

P1373 小a和uim之大逃离

转自:http://www.cnblogs.com/CtsNevermore/p/6028138.html 题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发.青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”.小a和他的小伙伴都惊呆了! 题目描述 瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不

洛谷P1373 小a和uim之大逃离

题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发.青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”.小a和他的小伙伴都惊呆了! 题目描述 瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液.怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任

洛谷 P1373 小a和uim之大逃离

题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发.青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”.小a和他的小伙伴都惊呆了! 题目描述 瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液.怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任

luogu P1373 小a和uim之大逃离

题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发.青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”.小a和他的小伙伴都惊呆了! 题目描述 瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液.怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任

洛谷 P1373 小a和uim之大逃离 不会

题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发.青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”.小a和他的小伙伴都惊呆了! 题目描述 瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液.怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任

洛谷OJ 1373 小a和uim之大逃离 DP

https://www.luogu.org/problem/show?pid=1373 题意:n*m地图,n,m<=800,起点,终点任意,两个人每次轮流取出点中的数并膜K,问走奇数次 两人取值相同的方法数? 只关心两人取的值是否相等,则记录差值即可 起点和终点任意 则设状态dp[i][j][k][p] 到达点(i,j)差值为k 并且由p取数的方法数不用枚举起点,暴力把所有状态的方案都计算出来即可,复杂度为O(n*m*k) #include <bits/stdc++.h> using n

小a和uim之大逃离(luogu P1373 dp)

小a和uim之大逃离(luogu P1373 dp) 给你一个n*m的矩阵,其中元素的值在1~k内.限制只能往下和往右走,问从任意点出发,到任意点结束,且经过了偶数个元素的合法路径有多少个.在此题中,定义在一条路径中,第奇数个元素之和为X,第偶数个元素之和为Y.X+Y同模k+1的路径是合法路径.答案模1e9+7.n,m<=800,1<=k<=15. 状态是\(f[i][j][h][0/1]\),表示第i行第j列的元素,奇数元素和X-偶数元素和Y差为h,当前在路径中是第奇数个点或第偶数个点

AC日记——小A和uim之大逃离 II 洛谷七月月赛

小A和uim之大逃离 II 思路: spfa: 代码: #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f struct NodeType { int x,y,k; NodeType(int x_,int y_,int k_):x(x_),y(y_),k(k_){} NodeType(){} }; const int dx[5]={0,-1,0,1,0}; const int dy[5]={0,0,1,0,-

P3818 小A和uim之大逃离 II(洛谷月赛)

P3818 小A和uim之大逃离 II 题目背景 话说上回……还是参见 https://www.luogu.org/problem/show?pid=1373 吧 小a和uim再次来到雨林中探险.突然一阵南风吹来,一片乌云从南部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个牛头马面的怪物,低沉着声音说:“呵呵,既然你们来到这,两个都别活了!”.小a和他的小伙伴再次惊呆了! 题目描述 瞬间,地面上出现了一个H行W列