【题解】LuoGu2254:[NOI2005]瑰丽华尔兹

原题传送门
首先还是暴力dp
d p t , x , y dp_{t,x,y} 表示时间 t t ,位置 ( x , y ) (x,y) 的答案

  • d p t , x , y < d p t 1 , x , y dp_{t,x,y}<---dp_{t-1,x,y}
  • d p t , x , y < d p t 1 , l s t x , l s t y + 1 dp_{t,x,y}<---dp_{t-1,lstx,lsty}+1

复杂度是 O ( t n 2 ) O(tn^2) ,可以拿到50分的好成绩

转换思路
d p t , x , y dp_{t,x,y} 表示第 t t 个时间段,最终位置在 ( x , y ) (x,y) 的答案
枚举上一个时间段的最终位置 ( l s t x , l s t y ) (lstx,lsty) ,因为两个时间段的位置一定共线,所以这一个枚举只需要 O ( n ) O(n)

  • d p t , x , y < d p t 1 , l s t x , l s t y + d i s t ( x , y , l s t x , l s t y ) dp_{t,x,y}<---dp_{t-1,lstx,lsty}+dist(x,y,lstx,lsty)

复杂度是 O ( k n 3 ) O(kn^3)
还是不行,考虑把枚举上一个时间段最终位置的循环用单调队列优化掉
时间变成了 O ( k n 2 ) O(kn^2) 可以过了
顺便把 d p dp 数组的第一维滚动掉,这样空间也满足要求了

Code:

#include <bits/stdc++.h>
#define maxn 210
using namespace std;
int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
struct node{
	int sum, pos;
}q[maxn];
int n, m, X, Y, k, dp[maxn][maxn], ans;
char s[maxn][maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void DP(int x, int y, int l, int d){
	int h = 1, t = 0;
	for (int i = 1; x && y && x <= n && y <= m; ++i, x += dx[d], y += dy[d])
		if (s[x][y] == 'x') h = 1, t = 0;
		else{
			while (h <= t && q[t].sum + i - q[t].pos <= dp[x][y]) --t;
			q[++t] = (node){dp[x][y], i};
			while (h <= t && i - q[h].pos > l) ++h;
			if (h <= t) ans = max(ans, dp[x][y] = q[h].sum + i - q[h].pos);
		}
}

int main(){
	n = read(), m = read(), X = read(), Y = read(), k = read();
	for (int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= m; ++j) dp[i][j] = -1e9;
	dp[X][Y] = 0;
	while  (k--){
		int s = read(), t = read(), d = read(), l = t - s + 1;
		if (d == 1) for (int i = 1; i <= m; ++i) DP(n, i, l, d);
		if (d == 2) for (int i = 1; i <= m; ++i) DP(1, i, l, d);
		if (d == 3) for (int i = 1; i <= n; ++i) DP(i, m, l, d);
		if (d == 4) for (int i = 1; i <= n; ++i) DP(i, 1, l, d);
	}
	printf("%d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108293693