【NOI2005】 瑰丽华尔兹
题目描述
瑰丽华尔兹 【任务描述】 你跳过华尔兹吗?当音乐响起,当你随着旋律滑动舞步,是不是有一种漫步 仙境的惬意? 众所周知,跳华尔兹时,最重要的是有好的音乐。但是很少有几个人知道, 世界上最伟大的钢琴家一生都漂泊在大海上, 他的名字叫丹尼·布德曼·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 为钢琴的初始位置;我们对船体倾斜情况是按时间的区间来描述的,且从 1 开始计算时间,比如“在[1, 3]时间里向东倾斜,[4, 5]时间里向北倾斜” ,因此这里的 K 表示区间的数目。 以下 N 行,每行 M 个字符,描述舞厅里的家具。 i 行第 j 列的字符若为‘ . ’, 则表示该位置是空地;若为‘ x ’,则表示有家具。 以下 K 行,顺序描述 K 个时间区间,格式为:si ti di(1 ≤ i ≤ K)。表示在时间 区间[si, ti]内,船体都是向 di 方向倾斜的。di 为 1, 2, 3, 4 中的一个,依次表示北、 南、西、东(分别对应矩阵中的上、下、左、右) 。输入保证区间是连续的,即 s1 = 1 ti = si-1 + 1 (1 < i ≤ K) tK = T 【输出格式】 输出文件仅有 1 行,包含一个整数,表示钢琴滑行的最长距离(即格子数)。 【输入样例】 45413 ..xx. ..... ...x. ..... 134 451 672 【输出样例】 6 【样例说明】 钢琴的滑行路线: 钢琴在“×”位置上时天使使用一次魔法,因此滑动总长度为 6。 【评分方法】 本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满 分,否则不得分。 【数据范围】 50%的数据中,1≤N, M≤200,T≤200; 第 3 页 共 10 页 Http://www.noi.cn 100%的数据中,1≤N, M≤200,K≤200,T≤40000。
样例说明:
动态规划(朴素)
1 (* 2 *Problem: 瑰丽的华尔兹 3 *Author : Chen Yang 4 *Time : 2012.6.3 8:30 am 5 *State : 70分 6 *Memo : 朴素DP 7 *) 8 program adv1900; 9 const 10 move:array[1..4,1..2] of longint=((1,0),(-1,0),(0,1),(0,-1)); 11 var 12 n,m,k,x,y,i,j,i1,p,ans,this,past:longint; 13 map:array[0..201,0..201] of char; 14 f:array[0..1,0..201,0..201] of longint; 15 t,s:array[0..300] of longint; 16 //========================= 17 begin 18 assign(input,'adv1900.in'); reset(input); 19 assign(output,'adv1900.out'); rewrite(output); 20 readln(n,m,x,y,k); 21 for i:=1 to n do 22 begin 23 for j:=1 to m do read(map[i,j]); 24 readln; 25 end; 26 for i:=1 to k do 27 begin 28 read(j,i1,s[i]); 29 t[i]:=i1-j+1; 30 end; 31 fillchar(f,sizeof(f),200); 32 this:=1; past:=0; 33 f[this,x,y]:=0; 34 for i1:=1 to k do 35 begin 36 this:=this xor 1; past:=past xor 1; 37 fillchar(f[this],sizeof(f[this]),200); 38 for i:=1 to n do 39 for j:=1 to m do 40 if map[i,j]='.' then 41 begin 42 for p:=0 to t[i1] do 43 begin 44 //writeln(x,' ',y); 45 x:=i+p*move[s[i1],1]; y:=j+p*move[s[i1],2]; 46 if (x<1)or(y<1)or(x>n)or(y>m)or(map[x,y]='x') then break; 47 if f[this,i,j]<f[past,x,y]+p then f[this,i,j]:=f[past,x,y]+p; 48 end; 49 //writeln(i1,' ',i,' ',j,' ',f[this,i,j]); 50 end; 51 end; 52 ans:=0; 53 for i:=1 to n do 54 for j:=1 to m do 55 if ans<f[this,i,j] then ans:=f[this,i,j]; 56 writeln(ans); 57 close(input); close(output); 58 end.
动态规划(单调队列优化)
1 (* 2 *Problem: 瑰丽的华尔兹 3 *Author : Chen Yang 4 *Time : 2012.6.3 12:00 am 5 *State : Sloved 6 *Memo : 单调队列优化DP 7 *) 8 program adv1900; 9 var 10 n,m,k,x,y,i,j,i1,ans,this,past,l,r:longint; 11 map:array[0..201,0..201] of char; 12 f:array[0..1,0..201,0..201] of longint; 13 t,s,dui:array[0..300] of longint; 14 //========================= 15 begin 16 assign(input,'adv1900.in'); reset(input); 17 assign(output,'adv1900.out'); rewrite(output); 18 readln(n,m,x,y,k); 19 for i:=1 to n do 20 begin 21 for j:=1 to m do read(map[i,j]); 22 readln; 23 end; 24 for i:=1 to k do 25 begin 26 read(j,i1,s[i]); 27 t[i]:=i1-j+1; 28 end; 29 fillchar(f,sizeof(f),200); 30 this:=1; past:=0; 31 if map[x,y]<>'x' then f[this,x,y]:=0; 32 for i1:=1 to k do 33 begin 34 this:=this xor 1; past:=past xor 1; 35 fillchar(f[this],sizeof(f[this]),200); 36 case s[i1] of 37 1:for j:=1 to m do 38 begin 39 l:=0; r:=0; 40 for i:=n downto 1 do 41 begin 42 if map[i,j]='x' then begin l:=0; r:=0; end; 43 while (l<r)and(dui[l+1]>i+t[i1]) do inc(l); 44 while (l<r)and(f[past,dui[r],j]+dui[r]-i<f[past,i,j]) do dec(r); 45 inc(r); dui[r]:=i; 46 f[this,i,j]:=f[past,dui[l+1],j]+dui[l+1]-i; 47 end; 48 end; 49 2:for j:=1 to m do 50 begin 51 l:=0; r:=0; 52 for i:=1 to n do 53 begin 54 if map[i,j]='x' then begin l:=0; r:=0; end; 55 while (l<r)and(dui[l+1]<i-t[i1]) do inc(l); 56 while (l<r)and(f[past,dui[r],j]+i-dui[r]<f[past,i,j]) do dec(r); 57 inc(r); dui[r]:=i; 58 f[this,i,j]:=f[past,dui[l+1],j]+i-dui[l+1]; 59 end; 60 end; 61 3:for i:=1 to n do 62 begin 63 l:=0; r:=0; 64 for j:=m downto 1 do 65 begin 66 if map[i,j]='x' then begin l:=0; r:=0; end; 67 while (l<r)and(dui[l+1]>j+t[i1]) do inc(l); 68 while (l<r)and(f[past,i,dui[r]]+dui[r]-j<f[past,i,j]) do dec(r); 69 inc(r); dui[r]:=j; 70 f[this,i,j]:=f[past,i,dui[l+1]]+dui[l+1]-j; 71 end; 72 end; 73 4:for i:=1 to n do 74 begin 75 l:=0; r:=0; 76 for j:=1 to m do 77 begin 78 if map[i,j]='x' then begin l:=0; r:=0; end; 79 while (l<r)and(dui[l+1]<j-t[i1]) do inc(l); 80 while (l<r)and(f[past,i,dui[r]]+j-dui[r]<f[past,i,j]) do dec(r); 81 inc(r); dui[r]:=j; 82 f[this,i,j]:=f[past,i,dui[l+1]]+j-dui[l+1]; 83 end; 84 end; 85 end; 86 end; 87 ans:=0; 88 for i:=1 to n do 89 for j:=1 to m do 90 if ans<f[this,i,j] then ans:=f[this,i,j]; 91 writeln(ans); 92 close(input); close(output); 93 end.