“21 天好习惯”第一期-1

A Mio visits ACGN Exhibition

题意

有一个 n ∗ m n*m nm 01 01 01 矩阵,起点在 ( 1 , 1 ) (1,1) (1,1) 终点在 ( n , m ) (n,m) (n,m) ,每次只能往右或者往左,问从起点走到终点,路过的网格点中 0 0 0 的个数大于 p p p 1 1 1 的个数大于 q q q 的路径有多少条

solution

朴素 bfs 中存储状态太多,会 mle,因此考虑动态规划

d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l] 表示当从起点走到 ( i , j ) (i,j) (i,j) 时, 0 0 0 的个数为 k k k 1 1 1 的个数为 l l l 的路径数量,则可以简单推到当这个结点往右走或者往下走的下一个状态情况。

四维数组肯定开不下,已知当前抵达 ( i , j ) (i,j) (i,j) ,则易得当前已经走过 i + j − 1 i+j-1 i+j1 个结点,那么就可以通过知道 0 0 0 的数量知道 1 1 1 的数量,这样可以砍掉一维。

但是还是不够,考虑滚动数组优化

每次状态转移对于 ( 1 , 1 ) (1,1) (1,1) 转移到的状态为 ( 1 , 2 ) (1,2) (1,2) ( 2 , 1 ) (2,1) (2,1) ,接下来是 ( 3 , 1 ) (3,1) (3,1) ( 2 , 2 ) (2,2) (2,2) ( 1 , 3 ) (1,3) (1,3) ,因此斜着遍历矩阵,每次更新完下个状态后,当前状态则可被替换,这样将第一维优化至2.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 507;
const int mod = 998244353;
int a[N][N];
const int M = 1e4 + 7;
int dp[2][N][500 + 500 + 10];
int n, m;
int p, q;
inline int read() {
    int s = 0, f = 1;
    char ch;
    do {
        ch = getchar();
        if (ch == '-')
            f = -1;
    } while (ch < 48 || ch > 57);
    while (ch >= 48 && ch <= 57) {
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    }
    return s * f;
}
signed main() {
    n = read(), m = read(), p = read(), q = read();
    rep(i, 1, n) rep(j, 1, m) a[i][j] = read();
    int c0 = (a[1][1] == 0), c1 = (a[1][1] == 1);
    dp[1][1][c0] = 1;
    rep(_, 2, n + m) 
        // 斜着去遍历 _ = i + j
        for (int i = 1; i <= n; ++i) {
            int j = _ - i;
            if (j > m || j <= 0)
                continue;
            int x = i & 1, y = x ^ 1;
            rep(k, 0, n + m ) {
                if(dp[x][j][k]==0) continue;
                int d = k + (a[i + 1][j] == 0), r = k + (a[i][j + 1] == 0);
                dp[x][j + 1][r] = (dp[x][j + 1][r] + dp[x][j][k]) % mod;
                dp[y][j][d] = (dp[y][j][d] + dp[x][j][k]) % mod;
                if(i!=n)
                dp[x][j][k]=0;
            }
        }
    long long ans = 0;
    rep(i, p, 1e3 + 1) if (n + m - 1 - i >= q) ans = (ans+ dp[n & 1][m][i])%mod;
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值