1. 程式人生 > >BZOJ1499 [NOI2005]瑰麗華爾茲 【單調隊列優化dp】

BZOJ1499 [NOI2005]瑰麗華爾茲 【單調隊列優化dp】

body 單調隊列優化 整數 amp space lin div 文件的 偉大的

題目

你跳過華爾茲嗎?當音樂響起,當你隨著旋律滑動舞步,是不是有一種漫步仙境的愜意?眾所周知,跳華爾茲時,最重要的是有好的音樂。但是很少有幾個人知道,世界上最偉大的鋼琴家一生都漂泊在大海上,他的名字叫丹尼?布德曼?T.D.?檸檬?1900,朋友們都叫他1900。 1900在20世紀的第一年出生在往返於歐美的郵輪弗吉尼亞號上,很不幸他剛出生就被拋棄了,成了孤兒。1900孤獨的成長在弗吉尼亞號上,從未離開過這個搖晃的世界。也許是對他命運的補償,上帝派可愛的小天使艾米麗照顧他。可能是天使的點化,1900擁有不可思議的鋼琴天賦:從未有人教,從沒看過樂譜,但他卻能憑著自己的感覺彈出最沁人心脾的旋律。當1900的音樂獲得郵輪上所有人的歡迎時,他才8歲,而此時的他已經乘著海輪往返歐美大陸50余次了。雖說是鋼琴奇才,但1900還是個孩子,他有著和一般男孩一樣的好奇和調皮,只不過更多一層浪漫的色彩罷了:這是一個風雨交加的夜晚,海風卷起層層巨浪拍打著弗吉尼亞號,郵輪隨著巨浪劇烈的搖擺。船上的新薩克斯手馬克斯?托尼暈船了,1900招呼托尼和他一起坐上舞廳裏的鋼琴,然後松開了固定鋼琴的閘,於是,鋼琴隨著海輪的傾斜滑動起來。準確的說,我們的主角1900、鋼琴、郵輪隨著1900的旋律一起跳起了華爾茲,隨著“嘣嚓嚓”的節奏,托尼的暈船癥也奇跡般的消失了。後來托尼在回憶錄上寫道:大海搖晃著我們使我們轉來轉去快速的掠過燈和家具我意識到我們正在和大海一起跳舞真是完美而瘋狂的舞者晚上在金色的地板上快樂的跳著華爾茲是不是很愜意呢?也許,我們忘記了一個人,那就是艾米麗,她可沒閑著:她必須在適當的時候施展魔法幫助1900,不讓鋼琴碰上舞廳裏的家具。不妨認為舞廳是一個N行M列的矩陣,矩陣中的某些方格上堆放了一些家具,其他的則是空地。鋼琴可以在空地上滑動,但不能撞上家具或滑出舞廳,否則會損壞鋼琴和家具,引來難纏的船長。每個時刻,鋼琴都會隨著船體傾斜的方向向相鄰的方格滑動一格,相鄰的方格可以是向東、向西、向南或向北的。而艾米麗可以選擇施魔法或不施魔法:如果不施魔法,則鋼琴會滑動;如果施魔法,則鋼琴會原地不動。艾米麗是個天使,她知道每段時間的船體的傾斜情況。她想使鋼琴在舞廳裏滑行路程盡量長,這樣1900會非常高興,同時也有利於治療托尼的暈船。但艾米麗還太小,不會算,所以希望你能幫助她。

輸入格式

輸入文件的第一行包含5個數N, M, x, y和K。N和M描述舞廳的大小,x和y為鋼琴的初始位置(x行y列);我們對船體傾斜情況是按時間的區間來描述的,且從1開始計量時間,比如“在[1, 3]時間裏向東傾斜,[4, 5]時間裏向北傾斜”,因此這裏的K表示區間的數目。以下N行,每行M個字符,描述舞廳裏的家具。第i行第j列的字符若為‘ . ’,則表示該位置是空地;若為‘ x ’,則表示有家具。以下K行,順序描述K個時間區間,格式為:si ti di。表示在時間區間[si, ti]內,船體都是向di方向傾斜的。di為1, 2, 3, 4中的一個,依次表示北、南、西、東(分別對應矩陣中的上、下、左、右)。輸入保證區間是連續的,即 s1 = 1 si = ti-1 + 1 (1 < i ≤ K) tK = T

輸出格式

輸出文件僅有1行,包含一個整數,表示鋼琴滑行的最長距離(即格子數)。

輸入樣例

4 5 4 1 3

..xx.

.....

...x.

.....

1 3 4

4 5 1

6 7 3

輸出樣例

6

題解

lrj的題誒,,果然是dp呢,,
我們設\(f[k][i][j]\)表示第k個時間段在點(i,j)的最大滑動距離
顯然\(f[k][i][j]\)是由一側方向的若幹個點之間滑來的【若幹個點數量為第k段時間長度】

以向右為例
\(f[k][i][j] = max(f[k - 1][i][L] + j - L)\)
暴力轉移\(O(n^4)\)

不那麽暴力點的話,會發現我們實際是求\(f[k][i][L] - L\)

最大,上一個單調隊列維護就好了
\(O(n^3)\)跑過

我比較懶,代碼就直接分四種情況寫了

#include<iostream>
#include<cstdio>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 205,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - ‘0‘; c = getchar();}
    return out * flag;
}
int n,m,Sx,Sy,K,f[maxn][maxn][maxn],len[maxn],way[maxn],q[maxn],head,tail;
char s[maxn][maxn];
int main(){
    int l,r;
    n = read(); m = read(); Sx = read(); Sy = read(); K = read();
    for (int i = 1; i <= n; i++) scanf("%s",s[i] + 1);
    for (int i = 1; i <= K; i++){
        l = read(); r = read(); way[i] = read();
        len[i] = r - l + 1;
    }
    REP(i,n) REP(j,m) f[0][i][j] = -INF;
    f[0][Sx][Sy] = 0;
    for (int k = 1; k <= K; k++){
        if (way[k] == 1){
            for (int j = 1; j <= m; j++){
                head = 0; tail = -1;
                for (int i = n; i; i--){
                    if (s[i][j] == ‘x‘){head = 0; tail = -1; continue;}
                    while (head <= tail && q[head] - len[k] > i) head++;
                    while (head <= tail && f[k - 1][q[tail]][j] + q[tail] < f[k - 1][i][j] + i) tail--;
                    q[++tail] = i;
                    f[k][i][j] = f[k - 1][q[head]][j] + q[head] - i;
                    
                }
            }
        }
        if (way[k] == 2){
            for (int j = 1; j <= m; j++){
                head = 0; tail = -1;
                for (int i = 1; i <= n; i++){
                    if (s[i][j] == ‘x‘){head = 0; tail = -1; continue;}
                    while (head <= tail && q[head] + len[k] < i) head++;
                    while (head <= tail && f[k - 1][q[tail]][j] - q[tail] < f[k - 1][i][j] - i) tail--;
                    q[++tail] = i;
                    f[k][i][j] = f[k - 1][q[head]][j] - q[head] + i;
                }
            }
        }
        if (way[k] == 3){
            for (int i = 1; i <= n; i++){
                head = 0; tail = -1;
                for (int j = m; j; j--){
                    if (s[i][j] == ‘x‘){head = 0; tail = -1; continue;}
                    while (head <= tail && q[head] - len[k] > j) head++;
                    while (head <= tail && f[k - 1][i][q[tail]] + q[tail] < f[k - 1][i][j] + j) tail--;
                    q[++tail] = j;
                    f[k][i][j] = f[k - 1][i][q[head]] - j + q[head];
                }
            }
        }
        if (way[k] == 4){
            for (int i = 1; i <= n; i++){
                head = 0; tail = -1;
                for (int j = 1; j <= m; j++){
                    if (s[i][j] == ‘x‘){head = 0; tail = -1; continue;}
                    while (head <= tail && q[head] + len[k] < j) head++;
                    while (head <= tail && f[k - 1][i][q[tail]] - q[tail] < f[k - 1][i][j] - j) tail--;
                    q[++tail] = j;
                    f[k][i][j] = f[k - 1][i][q[head]] + j - q[head];
                }
            }
        }
    }
    int ans = 0;
    REP(i,n) REP(j,m) if (s[i][j] == ‘.‘) ans = max(ans,f[K][i][j]);
    printf("%d\n",ans);
    return 0;
}

BZOJ1499 [NOI2005]瑰麗華爾茲 【單調隊列優化dp】