2091F Div. 3 Round 1013

题意

一个 \(n \times m\) 的矩阵 , 其中有些点为X

现在一个人从最底层任意一个X位向上走到最顶层

规则:

  1. 每层最多过两个X , 最少过一个X

  2. 层间移动和层内移动都只能在X上走 , 且两个X的距离不超过 \(k\)

问有多少种走的可能

思路

动态规划

分析可知 , 设 \(a_{i,j}\) 表示第 \(i\) 层 , 第 \(j\) 个X的横坐标 , \(f_{i,a_{i,j}}\) 为到达第 \(i\) 层 , 横坐标为 \(a_{i,j}\) 的路径数

那么该处的路径有两种可能:

第一种是从同层左右转移而来 , 也就是 \([a_{i,j} - k , a_{i,j} + k]\) 区间内所有其他同层点

第二种是从上层转移过来 , 为\([a_{i,j} - k , a_{i,j} + k]\) 区间内所有其他上层点

首先应该计算哪个呢 ?

显然应该计算上层来的 , 然后计算同层转移的

此时可以发现实际上区间长度是固定的 , 因而双指针求解

需要注意 , 当计算同层点时会将自己覆盖 , 需要另外开一个数组储存

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long int
inline int read() {
    int ans = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')f = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans * f;
}
const int N =2005;
const int mod = 998244353;
int a[N][N],tmp[N];
char g[N][N];
int n, m ,dis,ds;
void lr(int row) {
    memset(tmp, 0, sizeof tmp);
    int sum = a[row][1];
    int l = 1,r= 1;

    for (int i =1; i<= m ; i++) {
        if (g[row][i] !='X')
            continue;
        while (r + 1 <= m && r+1-i<=dis) {
            sum += a[row][++r];
            sum += mod;
            sum %= mod;
        }
        while (i - l > dis) {
            sum -= a[row][l++];
            sum += mod;
            sum %= mod;
        }
        tmp[i] = sum;

    }
    for (int i =1; i<= m; i++) {
        a[row][i] = tmp[i];
    }

    return ;
}
void up(int row) {
    int l = 1,r =1;
    int sum = a[row][1];
    for (int i =1; i<= m; i++) {
        if (g[row-1][i] !='X')
            continue;
        while (r+1 <= m && r+1-i<=ds) {
            sum += a[row][++r];
            sum += mod;
            sum %= mod;
        }
        while (i-l > ds) {
            sum -= a[row][l++];
            sum += mod;
            sum %= mod;

        }
        a[row-1][i] = sum;
    }
    return ;

}
void solve() {
    memset(a,0,sizeof a);
    n =read(), m= read(),dis=read();
    ds = (int) sqrt(dis * dis -1);
    for (int i =1; i<= n; i++) {
        for (int j =1; j<= m; j++) {
            scanf("%c",&g[i][j]);
        }
        char ch = getchar();
    }
    for (int i =1; i<= m; i++) {
        if (g[n][i] =='X')
            a[n][i] = 1;
    }
    for (int i =n; i>=1; i--) {
        lr(i);
        if (i==1)
            break;
        up(i);
    }
    int ans =0 ;
    for (int i =1; i<= m; i++) {
        ans += a[1][i];
        ans += mod;
        ans %= mod;
    }
    cout<<ans<<"\n";
}
signed main() {
    int t= read();
    while (t--) solve();
    return 0;
}

posted @ 2025-03-26 23:00  Guaninf  阅读(11)  评论(0)    收藏  举报