zstu3924 [NOI2005]瑰丽华尔兹 (单调队列dp)
题意:中文不解释。。
解题思路:先列出dp状态,dp[i][j][k]表示在k时刻,停留在(i,j)位置时,能走的最长的路程。但是我后来在网上查了下数据范围,i,j<=200,k<=40000这样直接做是会超时,超内存的,那么用单调队列优化下。用dp[i][j][k]表示在第k个时间段,在(i,j)位置时,能走的最长路程,注意,这里的k表示的是时间段了,而不是时间点,设这个时间段的长度为l,假设这时候船的倾斜方向为向右,那么我们一行一行分析,假设当前是第i行,对于第j列的时候,能走的最长路程为dp[i][j][k],假设其最大值是从t位置推过来的,那么,对于第j+1的位置,至少应该是从t位置推过来,这个就是单调性了(其他方向是类似的做法)。还有就是k那一维用滚动数组,否则卡内存。整体时间复杂度为o(n*m*k),看起来还是会超时的样子,不过也只能这样了。
表达能力实在是有限。。如果有什么疑问或者见解可以留言讨论。
#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int INF = -1111111 ;
const int maxn = 222 ;
char mp[maxn][maxn] ;
int dp[2][maxn][maxn] , g , t ;
int n , m , x , y , k ;
struct Deque {
int val[maxn] , pos[maxn] ;
int star , tail ;
void init () {
star = 1 , tail = 0 ;
}
void pop () {
if ( star <= tail ) star ++ ;
}
void push ( int id , int v ) {
while ( star <= tail && val[tail] < v ) tail -- ;
val[++tail] = v ;
pos[tail] = id ;
}
} q ;
void solve ( int l , int c ) {
int i , j ;
if ( c == 1 ) {
for ( i = 1 ; i <= m ; i ++ ) {
q.init () ;
int last = 0 ;
for ( j = n ; j >= 1 ; j -- ) {
if ( mp[j][i] == 'x' ) {
q.init () ;
continue ;
}
q.push ( j , dp[g][j][i] + j ) ;
while ( q.pos[q.star] > j + l ) q.star ++ ;
last = q.pos[q.star] ;
dp[t][j][i] = max ( dp[t][j][i] , dp[g][last][i] + last - j ) ;
dp[t][j][i] = max ( dp[t][j][i] , dp[g][j][i] ) ;
}
}
}
else if ( c == 2 ) {
for ( i = 1 ; i <= m ; i ++ ) {
q.init () ;
int last = 0 ;
for ( j = 1 ; j <= n ; j ++ ) {
if ( mp[j][i] == 'x' ) {
q.init () ;
continue ;
}
q.push ( j , dp[g][j][i] - j ) ;
while ( q.pos[q.star] < j - l ) q.star ++ ;
last = q.pos[q.star] ;
dp[t][j][i] = max ( dp[t][j][i] , dp[g][last][i] + j - last ) ;
dp[t][j][i] = max ( dp[t][j][i] , dp[g][j][i] ) ;
}
}
}
else if ( c == 3 ) {
for ( i = 1 ; i <= n ; i ++ ) {
q.init () ;
int last = 0 ;
for ( j = m ; j >= 1 ; j -- ) {
if ( mp[i][j] == 'x' ) {
q.init () ;
continue ;
}
q.push ( j , dp[g][i][j] + j ) ;
while ( q.pos[q.star] > j + l ) q.star ++ ;
last = q.pos[q.star] ;
dp[t][i][j] = max ( dp[t][i][j] , dp[g][i][last] - j + last ) ;
dp[t][i][j] = max ( dp[t][i][j] , dp[g][i][j] ) ;
// printf ( "fuck dp[%d][%d] = %d\n" , i , j , dp[t][i][j] ) ;
// printf ( "dp[%d][%d] = %d\n" , i , last , dp[g][i][last] ) ;
}
}
}
else {
for ( i = 1 ; i <= n ; i ++ ) {
q.init () ;
int last = 0 ;
for ( j = 1 ; j <= m ; j ++ ) {
if ( mp[i][j] == 'x' ) {
q.init () ;
continue ;
}
q.push ( j , dp[g][i][j] - j ) ;
while ( q.pos[q.star] < j - l ) q.star ++ ;
last = q.pos[q.star] ;
dp[t][i][j] = max ( dp[t][i][j] , dp[g][i][last] + j -last ) ;
dp[t][i][j] = max ( dp[t][i][j] , dp[g][i][j] ) ;
}
}
}
}
int main() {
int i , j ;
while ( scanf ( "%d%d%d%d%d" , &n , &m , &x , &y , &k ) != EOF ) {
for ( i = 1 ; i <= n ; i ++ )
scanf ( "%s" , mp[i] + 1 ) ;
g = 0 ;
t = 1 ;
for ( i = 1 ; i <= n ; i ++ )
for ( j = 1 ; j <= m ; j ++ )
dp[g][i][j] = dp[t][i][j] = INF ;
dp[g][x][y] = 0 ;
for ( i = 1 ; i <= k ; i ++ ) {
int a , b , c ;
scanf ( "%d%d%d" , &a , &b , &c ) ;
solve ( b - a + 1 , c ) ;
swap ( g , t ) ;
// for ( j = 1 ; j <= n ; j ++ )
// for ( a = 1 ; a <= m ; a ++ )
// printf ( "dp[%d][%d] = %d\n" , j , a , dp[g][j][a] ) ;
}
int ans = 0 ;
for ( i = 1 ; i <= n ; i ++ )
for ( j = 1 ; j <= m ; j ++ )
ans = max ( ans , dp[g][i][j] ) ;
printf ( "%d\n" , ans ) ;
}
return 0;
}