[NOI 2005]瑰丽华尔兹

Description

题库链接

给你一张 \(n\times m\) 的棋盘,棋盘上有一些障碍。一共 \(t\) 个时刻,被分为 \(k\) 段,在每一段中都有一个向上/下/左/右倾斜的趋势(持续时间 \(q_i\))。

1 时刻一架钢琴在 \((x_0,y_0)\) 处,你可以在任意时刻控制它动或不动,若动则该时刻会向趋势方向滑动一格。要求在任何时刻都不能出棋盘或碰到障碍,问你 \(t\) 时刻内最多滑动多少格。

\(1\leq n,m,k\leq 200\)

Solution

\(f_{i,x,y}\) 为第 \(i\sim k\) 个时段 \(i\) 时段初始时候在 \((x,y)\) 处的最小花费。则答案为 \(f_{1,x_0,y_0}\)

假设第 \(i\) 个时段向左滑,那么 \(f_{i,x,y}=\max\limits_{x-a\leq q_i}f_{i+1,a,y}+x-a\),其中 \((a,y)\sim(x,y)\) 中无障碍。

容易发现 \(a\) 是可以用单调队列优化的。

其余方向同理。总复杂度 \(O(nmk)\)

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 205;

int n, m, x, y, k, mp[N][N], s[N], t[N], d[N], f[2][N][N], id;
int q[N], head, tail;
char ch[N];

void work1(int j) {
    head = 1, tail = 0;
    for (int i = 1; i <= n; i++) {
        if (mp[i][j]) {head = 1, tail = 0; continue; }
        while (head <= tail && f[0][q[tail]][j]-q[tail] < f[0][i][j]-i) --tail;
        q[++tail] = i;
        while (i-q[head] > t[id]) ++head;
        f[1][i][j] = f[0][q[head]][j]+i-q[head];
    }
}
void work2(int j) {
    head = 1, tail = 0;
    for (int i = n; i >= 1; i--) {
        if (mp[i][j]) {head = 1, tail = 0; continue; }
        while (head <= tail && f[0][q[tail]][j]+q[tail] < f[0][i][j]+i) --tail;
        q[++tail] = i;
        while (q[head]-i > t[id]) ++head;
        f[1][i][j] = f[0][q[head]][j]+q[head]-i;
    }
}
void work3(int i) {
    head = 1, tail = 0;
    for (int j = 1; j <= m; j++) {
        if (mp[i][j]) {head = 1, tail = 0; continue; }
        while (head <= tail && f[0][i][q[tail]]-q[tail] < f[0][i][j]-j) --tail;
        q[++tail] = j;
        while (j-q[head] > t[id]) ++head;
        f[1][i][j] = f[0][i][q[head]]+j-q[head];
    }
}
void work4(int i) {
    head = 1, tail = 0;
    for (int j = m; j >= 1; j--) {
        if (mp[i][j]) {head = 1, tail = 0; continue; }
        while (head <= tail && f[0][i][q[tail]]+q[tail] < f[0][i][j]+j) --tail;
        q[++tail] = j;
        while (q[head]-j > t[id]) ++head;
        f[1][i][j] = f[0][i][q[head]]+q[head]-j;
    }
}
int main() {
    scanf("%d%d%d%d%d", &n, &m, &x, &y, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%s", ch+1);
        for (int j = 1; j <= m; j++) mp[i][j] = ch[j] == 'x';
    }
    for (int i = 1; i <= k; i++) scanf("%d%d%d", &s[i], &t[i], &d[i]), t[i] = t[i]-s[i]+1;
    for (id = k; id >= 1; id--) {
        memcpy(f[0], f[1], sizeof(f[0]));
        memset(f[1], 0, sizeof(f[0]));
        if (d[id] == 1) for (int i = 1; i <= m; i++) work1(i);
        else if (d[id] == 2) for (int i = 1; i <= m; i++) work2(i);
        else if (d[id] == 3) for (int i = 1; i <= n; i++) work3(i);
        else if (d[id] == 4) for (int i = 1; i <= n; i++) work4(i);
    }
    printf("%d\n", f[1][x][y]);
    return 0;   
}

猜你喜欢

转载自www.cnblogs.com/NaVi-Awson/p/12239124.html