[NOI2005]瑰丽华尔兹
用单调队列优化的dp
dp[i][j][k]表在第i段时间走到(j,k)的步数
正常转移是n^5
但可以发现一段时间走的方向一定所以可以用单调队列优化
时间复杂度n^3
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,stx,sty,k,l,r,ans; int head,tail; char mp[205][205]; int tim[205]; int dp[255][205][205]; int dx[5]={0,-1,1,0,0}; int dy[5]={0,0,0,-1,1}; struct node{ int val; int pos; node(){} node(int val,int pos):val(val),pos(pos){} }que[205]; void DP(int x,int y,int t){ head=1,tail=0; for(int i=1;x>=1&&x<=n&&y>=1&&y<=m;i++,x+=dx[tim[t]],y+=dy[tim[t]]){ if(mp[x][y]=='x'){ head=1,tail=0; continue; } while(tail>=head&&dp[t-1][x][y]>que[tail].val+i-que[tail].pos)tail--; que[++tail]=node(dp[t-1][x][y],i); if(que[tail].pos-que[head].pos>r-l+1)head++; dp[t][x][y]=que[head].val+i-que[head].pos; ans=max(ans,dp[t][x][y]); } } int main(){ scanf("%d%d%d%d%d",&n,&m,&stx,&sty,&k); for(int i=1;i<=n;i++){ scanf("%s",mp[i]+1); } for(int i=0;i<=k;i++){ for(int j=1;j<=n;j++){ for(int z=1;z<=m;z++){ dp[i][j][z]=-0x3f3f3f3f; } } } dp[0][stx][sty]=0; for(int i=1;i<=k;i++){ scanf("%d%d%d",&l,&r,&tim[i]); if(tim[i]==1){ for(int j=1;j<=m;j++){ DP(n,j,i); } } if(tim[i]==2){ for(int j=1;j<=m;j++){ DP(1,j,i); } } if(tim[i]==3){ for(int j=1;j<=n;j++){ DP(j,m,i); } } if(tim[i]==4){ for(int j=1;j<=n;j++){ DP(j,1,i); } } } printf("%d\n",ans); return 0; }