T180750 棋盘游戏2

这个题好像没过,但是我依然要写博客


我们首先考虑暴力做,显然是\(O(n^3)\)
然后我们找性质
可以发现一个点转移到的其他点一定是在同一斜行上的(/)
这样我们可以优化dp顺序,一斜行一斜行的dp。
然而时间复杂度没有变。
但是我们可以发现在枚举到这一斜行时,这一斜行的值就已经确定了。
显然我们可以使用区间数据结构优化转移。
这样就是\(O(n^2\log n)\)的了。
因为线段树熟练,所以我写了线段树。
但是线段树常数钛大了,而且会爆空间。
所以我们只能用ST表。

标程如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 3005
using namespace std;
inline int read() {
    int ans = 0;
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
    return ans;
}
int a[MAXN][MAXN], st[12][MAXN][MAXN], LOG[MAXN];
int main() {
    LOG[0] = -1;
    for (int i = 1; i < MAXN; i++) LOG[i] = LOG[i >> 1] + 1;
    int n, m;
    n = read(), m = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) a[i][j] = read();
    for (int x = n; x >= 1; x--)
        for (int y = m; y >= 1; y--) {
            if (x == n && y == m)
                continue;
            st[0][x][y] = 1e9;
            int nx = x, ny = y + a[x][y];
            if (ny > m)
                nx += ny - m, ny = m;
            if (nx > n)
                continue;
            int l = min(n - nx + 1, ny - y + 1), t = LOG[l], mx = nx + l - 1, my = ny - l + 1;
            st[0][x][y] = min(st[t][nx][ny], st[t][mx - (1 << t) + 1][my + (1 << t) - 1]) + 1;
            l = min(n - x + 1, y);
            for (int i = 0; i < 11; i++)
                if ((1 << (i + 1)) <= l)
                    st[i + 1][x][y] = min(st[i][x][y], st[i][x + (1 << i)][y - (1 << i)]);
        }
    printf("%d\n", st[0][1][1]);
    return 0;
}
posted @ 2021-07-24 16:25  lei_yu  阅读(24)  评论(0编辑  收藏  举报