zstu3924 [NOI2005]瑰丽华尔兹 (单调队列dp)

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


你可能感兴趣的:(单调队列)