单调队列优化。。。f[k][i][j]表示k个时间段过后,走到点(i,j)时,最多已走过了多少个格子。
因为每个时间段内的方向都是一样的,所以用单调队列优化一下就好了。。。
这题其实就是个多重背包。。一段时间段的长度就是背包容量,而点(i,j)往某个方向最多能走多少格就是物品的数目,物品价值都为1.。所以抛开四种方向不说,这题好像比多重背包还简单点?
一开始写了一坨预处理出每个点往各个方向最大扩展长度,结果dp的时候发现似乎不用?。。。如果当前点为障碍点的话直接把单调队列清空就好了QAQ
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int maxn=203; 6 const int inf=1000023333; 7 const int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0}; 8 9 int dl[maxn]; 10 int f[2][maxn][maxn],mxstep[4][maxn][maxn];//0,1,2,3:向东向西向南向北 11 bool cant[maxn][maxn]; 12 int i,j,K,n,m,sx,sy,x,y,len,dir,ans,now,pre; 13 14 int ra;char rx; 15 inline int read(){ 16 rx=getchar(),ra=0; 17 while(rx<'0'||rx>'9')rx=getchar(); 18 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 19 } 20 21 inline void dp(int dir){ 22 int l,r;register int i,j; 23 if(dir==4){//船向东倾:由西边的点转移过来 24 for(i=1;i<=n;i++) 25 for(j=1,l=1,r=0;j<=m;j++)if(!cant[i][j]){ 26 while(l<=r&&f[pre][i][j]-j>=f[pre][i][dl[r]]-dl[r])r--; 27 dl[++r]=j; 28 while(l<r&&j-dl[l]>len)l++; 29 f[now][i][j]=f[pre][i][dl[l]]-dl[l]+j; 30 }else l=1,r=0; 31 }else 32 if(dir==3){ 33 for(i=1;i<=n;i++) 34 for(j=m,l=1,r=0;j;j--)if(!cant[i][j]){ 35 while(l<=r&&f[pre][i][j]+j>=f[pre][i][dl[r]]+dl[r])r--; 36 dl[++r]=j; 37 while(l<r&&dl[l]-j>len)l++; 38 f[now][i][j]=f[pre][i][dl[l]]+dl[l]-j; 39 }else l=1,r=0; 40 }else 41 if(dir==2){ 42 for(j=1;j<=m;j++) 43 for(i=1,l=1,r=0;i<=n;i++)if(!cant[i][j]){ 44 while(l<=r&&f[pre][i][j]-i>=f[pre][dl[r]][j]-dl[r])r--; 45 dl[++r]=i; 46 while(l<r&&i-dl[l]>len)l++; 47 f[now][i][j]=f[pre][dl[l]][j]-dl[l]+i; 48 }else l=1,r=0; 49 }else 50 if(dir==1){ 51 for(j=1;j<=m;j++) 52 for(i=n,l=1,r=0;i;i--)if(!cant[i][j]){ 53 while(l<=r&&f[pre][i][j]+i>=f[pre][dl[r]][j]+dl[r])r--; 54 dl[++r]=i; 55 while(l<r&&dl[l]-i>len)l++; 56 f[now][i][j]=f[pre][dl[l]][j]+dl[l]-i; 57 }else l=1,r=0; 58 } 59 // for(i=1;i<=n;puts(""),i++)for(j=1;j<=m;j++)printf(" %d",f[now][i][j]); 60 } 61 62 int main(){ 63 register int i,j; 64 n=read(),m=read(),sx=read(),sy=read(),K=read(); 65 for(i=1;i<=n;i++){ 66 for(rx=getchar();rx!='.'&&rx!='x';rx=getchar());cant[i][1]=rx=='x'; 67 for(j=2;j<=m;j++)cant[i][j]=getchar()=='x'; 68 } 69 70 for(i=1;i<=n;i++)memset(f[0][i],195,(m+1)<<2); 71 f[0][sx][sy]=0; 72 now=1,pre=0; 73 while(K--){ 74 j=read(),len=read()-j+1,dir=read(), 75 dp(dir);swap(now,pre); 76 } 77 for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(f[pre][i][j]>ans)ans=f[pre][i][j]; 78 printf("%d ",ans); 79 return 0; 80 } 81
因为每种方向都写了一发所以比较长(虽然是复制粘贴的= =)