1. 程式人生 > >●BZOJ 1499 [NOI2005]瑰麗華爾茲

●BZOJ 1499 [NOI2005]瑰麗華爾茲

set 表示 int home sin 模塊 ++ dp優化 log

題鏈:http://www.lydsy.com/JudgeOnline/problem.php?id=1499
題解:單調隊列優化DP定義 dp[t][x][y] 表示第t個時間段之後,處在(x,y)位置所滑過的最長距離。顯然 dp[t][x][y] 的來源就是 dp[t-1][x‘][y‘],表示由(x‘,y‘)這個點滑過來的。
所以枚舉t,x,y 以及滑行距離(以便得到(x‘,y‘)位置)進行DP,復雜度為kN3 然後考慮優化,對於某個方向的滑行,不需要每次都重新枚舉滑行距離,可以用一個單調隊列維護該點(x,y)的最優轉移來源,然後O(1)轉移,時間優化到 kN2代碼:#include<cstdio>#include<cstring>#include<iostream>#define MAXN 205using namespace std;const int mv[4][2]={{-1,0},{1,0},{0,-1},{0,1}};char MP[MAXN][MAXN];int dp[2][MAXN][MAXN];int N,M,X,Y,K,cur,ANS;int dis(int x,int y){
if(x<y) swap(x,y); return x-y;}void transfer(int x,int y,int k,int d){ static int val[MAXN],px[MAXN],py[MAXN],l,r; l=1; r=0; for(int i=1,now;1<=x&&x<=N&&1<=y&&y<=M;x+=mv[k][0],y+=mv[k][1],i++){ if(MP[x][y]==‘x‘){ while(l<=r) l++; dp[cur][x][y]=0; } else{
now=dp[cur^1][x][y]-i; while(l<=r&&val[r]<=now) r--; r++; val[r]=now; px[r]=x; py[r]=y; while(l<=r&&(dis(x,px[l])>d||dis(y,py[l])>d)) l++; dp[cur][x][y]=dp[cur^1][px[l]][py[l]]+dis(x,px[l])+dis(y,py[l]); } }}int main(){ freopen("/home/noilinux/Documents/模塊學習/DP優化/1499.in","r",stdin);
scanf("%d%d%d%d%d",&N,&M,&X,&Y,&K); memset(dp[cur],0xc0,sizeof(dp[cur])); dp[cur][X][Y]=0; for(int i=1;i<=N;i++) scanf("%s",MP[i]+1); for(int k=1,s,t,d;k<=K;k++){ cur^=1; scanf("%d%d%d",&s,&t,&d); if(d==1) for(int j=1;j<=M;j++) transfer(N,j,0,t-s+1); if(d==2) for(int j=1;j<=M;j++) transfer(1,j,1,t-s+1); if(d==3) for(int i=1;i<=N;i++) transfer(i,M,2,t-s+1); if(d==4) for(int i=1;i<=N;i++) transfer(i,1,3,t-s+1); } for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) ANS=max(ANS,dp[cur][i][j]); printf("%d\n",ANS); return 0;}

●BZOJ 1499 [NOI2005]瑰麗華爾茲