1. 程式人生 > >bzoj 1499 [NOI2005]瑰麗華爾茲 (單調隊列優化DP)

bzoj 1499 [NOI2005]瑰麗華爾茲 (單調隊列優化DP)

turn name main alt 刪除 upd pri 優化 mat

題目大意:給你一個n*m棋盤(n,m<=200),有一個人從給定的點s,e出發,有一些壞點不能走,一共給定k段連續的時間(k<=200),在某一段時間之內它只能向一個給定的方向移動,在某一時刻,它可以移動或者不移動。求碰到壞點之前/總時間結束時,最長移動的距離。

樸素DP的方法是: 技術分享圖片 表示在時間點t時,在位置(i,j)時已經走過的最長距離,i‘ j‘表示這一步移動前的位置

得到方程技術分享圖片

空間時間都會炸

那麽重新定義 技術分享圖片 表示在第k個時間段,在位置(i,j)時已經走過的最長距離

那麽顯然技術分享圖片,註意要根據移動的方向決定枚舉的順序

由於dis在同一行/列具有單調性,用隊列隨便優化一下就行了,如果dis大於t[i]-s[i]就刪除隊首,如果碰到障礙就清隊列

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #define N 205
  5 using namespace std;
  6 
  7 int n,m,sx,sy,K,now,pst;
  8 int mp[N][N],st[N],ed[N],dir[N],que[N];
  9 int xx[]={0,-1,1,0,0},yy[]={0,0,0,-1,1};
 10 char str[N][N];
 11 int f[2][N][N];
 12 void upd1(int
k) 13 { 14 int hd,tl; 15 for(int j=1;j<=m;j++) 16 { 17 hd=1,tl=0; 18 for(int i=n;i>=1;i--) 19 { 20 if(mp[i][j]) {hd=1,tl=0;continue;} 21 while(hd<=tl&&f[pst][que[tl]][j]+que[tl]-i<=f[pst][i][j]) 22 tl--;
23 que[++tl]=i; 24 while(hd<=tl&&que[hd]-i>ed[k]-st[k]+1) 25 hd++; 26 f[now][i][j]=f[pst][que[hd]][j]+que[hd]-i; 27 } 28 } 29 } 30 void upd2(int k) 31 { 32 int hd,tl; 33 for(int j=1;j<=m;j++) 34 { 35 hd=1,tl=0; 36 for(int i=1;i<=n;i++) 37 { 38 if(mp[i][j]) {hd=1,tl=0;continue;} 39 while(hd<=tl&&f[pst][que[tl]][j]+i-que[tl]<=f[pst][i][j]) 40 tl--; 41 que[++tl]=i; 42 while(hd<=tl&&i-que[hd]>ed[k]-st[k]+1) 43 hd++; 44 f[now][i][j]=f[pst][que[hd]][j]+i-que[hd]; 45 } 46 } 47 } 48 void upd3(int k) 49 { 50 int hd,tl; 51 for(int i=1;i<=n;i++) 52 { 53 hd=1,tl=0; 54 for(int j=m;j>=1;j--) 55 { 56 if(mp[i][j]) {hd=1,tl=0;continue;} 57 while(hd<=tl&&f[pst][i][que[tl]]+que[tl]-j<=f[pst][i][j]) 58 tl--; 59 que[++tl]=j; 60 while(hd<=tl&&que[hd]-j>ed[k]-st[k]+1) 61 hd++; 62 f[now][i][j]=f[pst][i][que[hd]]+que[hd]-j; 63 } 64 } 65 } 66 void upd4(int k) 67 { 68 int hd,tl; 69 for(int i=1;i<=n;i++) 70 { 71 hd=1,tl=0; 72 for(int j=1;j<=m;j++) 73 { 74 if(mp[i][j]) {hd=1,tl=0;continue;} 75 while(hd<=tl&&f[pst][i][que[tl]]+j-que[tl]<=f[pst][i][j]) 76 tl--; 77 que[++tl]=j; 78 while(hd<=tl&&j-que[hd]>ed[k]-st[k]+1) 79 hd++; 80 f[now][i][j]=f[pst][i][que[hd]]+j-que[hd]; 81 } 82 } 83 } 84 85 int main() 86 { 87 scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&K); 88 for(int i=1;i<=n;i++){ 89 scanf("%s",str[i]+1); 90 for(int j=1;j<=m;j++) 91 if(str[i][j]==x) 92 mp[i][j]=1; 93 } 94 for(int i=1;i<=K;i++) 95 scanf("%d%d%d",&st[i],&ed[i],&dir[i]); 96 memset(f,-0x3f,sizeof(f)); 97 f[0][sx][sy]=0; 98 now=1,pst=0; 99 for(int k=1;k<=K;k++) 100 { 101 if(dir[k]==1) upd1(k); 102 if(dir[k]==2) upd2(k); 103 if(dir[k]==3) upd3(k); 104 if(dir[k]==4) upd4(k); 105 swap(now,pst); 106 } 107 int ans=0; 108 for(int i=1;i<=n;i++) 109 for(int j=1;j<=m;j++) 110 ans=max(f[pst][i][j],ans); 111 printf("%d\n",ans); 112 return 0; 113 }

bzoj 1499 [NOI2005]瑰麗華爾茲 (單調隊列優化DP)