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