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;
}