P2254 [NOI2005] 瑰丽华尔兹

P2254 [NOI2005] 瑰丽华尔兹

不妨认为舞厅是一个 \(N\)\(M\) 列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地。钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅,否则会损坏钢琴和家具,引来难缠的船长。每个时刻,钢琴都会随着船体倾斜的方向向相邻的方格滑动一格,相邻的方格可以是向东、向西、向南或向北的。而艾米丽可以选择施魔法或不施魔法:如果不施魔法,则钢琴会滑动;如果施魔法,则钢琴会原地不动。

艾米丽是个天使,她知道每段时间的船体的倾斜情况。她想使钢琴在舞厅里滑行的路程尽量长,这样 1900 会非常高兴,同时也有利于治疗托尼的晕船。但艾米丽还太小,不会算,所以希望你能帮助她。

Solution

看范围支持 \(O(n^{3})\)
想一种暴力的方法, 用 \(dp[x][y]\) 维护当前操作后, 位于 \((x,y)\) 的最长距离
不用管他是哪个阶段的, 只要能转移获得最大值, 我就用魔法让他一直停在那就行
然后我们每次船倾斜时, 枚举每一个点, 更新他的dp值
显然在船倾斜时, 朝向是统一的, 所以更新的依据一定在前面某个区间内
拿单调队列把每行/列的维护控制在 \(O(n)\) 即可

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 210, inf = 1e9;
int lenx, leny;
int sx, sy;
int n, ans = -inf;
char map[maxn][maxn];
int dp[maxn][maxn];
void init(){
	lenx = RD(), leny = RD();
	sx = RD(), sy = RD();
	n = RD();
	REP(i, 1, lenx)REP(j, 1, leny){
		cin>>map[i][j];
		dp[i][j] = -inf;
		}
	dp[sx][sy] = 0;
	}
int mx[5] = {0, -1, 1, 0, 0};
int my[5] = {0, 0, 0, -1, 1};
struct Que{int val, Index;}Q[maxn];
void DP(int x, int y, int len, int d){//把从(x, y)沿着d方向运行len的dp全部滚掉一遍
	int head = 1, tail = 0;
	for(int i = 1;x && y && x <= lenx && y <= leny;i++, x += mx[d], y += my[d]){
		if(map[x][y] == 'x')head = 1, tail = 0;//重置
		else{
			while(head <= tail && Q[tail].val + i - Q[tail].Index <= dp[x][y])tail--;
			//因为被滚掉了所以先入队
			Q[++tail] = (Que){dp[x][y], i};
			while(head <= tail && i - Q[head].Index > len)head++;
			if(head <= tail)dp[x][y] = Q[head].val + i - Q[head].Index;
			ans = max(ans, dp[x][y]);
			}
		}
	}
void work(){
	while(n--){
		int s = RD(), t = RD(), d = RD();
		if(d == 1)REP(i, 1, leny)DP(lenx, i, t - s + 1, d);
		if(d == 2)REP(i, 1, leny)DP(1,    i, t - s + 1, d);
		if(d == 3)REP(i, 1, lenx)DP(i, leny, t - s + 1, d);
		if(d == 4)REP(i, 1, lenx)DP(i, 1,    t - s + 1, d);
		}
	cout<<ans<<endl;
	}
int main(){
	init();
	work();
	return 0;
	}
posted @ 2021-03-16 22:50  Tony_Double_Sky  阅读(45)  评论(0编辑  收藏  举报