您的位置:首页 > 其它

[bzoj1499] [NOI2005]瑰丽华尔兹

2016-02-13 11:18 253 查看
  单调队列优化。。。f[k][i][j]表示k个时间段过后,走到点(i,j)时,最多已走过了多少个格子。

  因为每个时间段内的方向都是一样的,所以用单调队列优化一下就好了。。。

  这题其实就是个多重背包。。一段时间段的长度就是背包容量,而点(i,j)往某个方向最多能走多少格就是物品的数目,物品价值都为1.。所以抛开四种方向不说,这题好像比多重背包还简单点?

  一开始写了一坨预处理出每个点往各个方向最大扩展长度,结果dp的时候发现似乎不用?。。。如果当前点为障碍点的话直接把单调队列清空就好了QAQ

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=203;
const int inf=1000023333;
const int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};

int dl[maxn];
int f[2][maxn][maxn],mxstep[4][maxn][maxn];//0,1,2,3:向东向西向南向北
bool cant[maxn][maxn];
int i,j,K,n,m,sx,sy,x,y,len,dir,ans,now,pre;

int ra;char rx;
inline int read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}

inline void dp(int dir){
int l,r;register int i,j;
if(dir==4){//船向东倾:由西边的点转移过来
for(i=1;i<=n;i++)
for(j=1,l=1,r=0;j<=m;j++)if(!cant[i][j]){
while(l<=r&&f[pre][i][j]-j>=f[pre][i][dl[r]]-dl[r])r--;
dl[++r]=j;
while(l<r&&j-dl[l]>len)l++;
f[now][i][j]=f[pre][i][dl[l]]-dl[l]+j;
}else l=1,r=0;
}else
if(dir==3){
for(i=1;i<=n;i++)
for(j=m,l=1,r=0;j;j--)if(!cant[i][j]){
while(l<=r&&f[pre][i][j]+j>=f[pre][i][dl[r]]+dl[r])r--;
dl[++r]=j;
while(l<r&&dl[l]-j>len)l++;
f[now][i][j]=f[pre][i][dl[l]]+dl[l]-j;
}else l=1,r=0;
}else
if(dir==2){
for(j=1;j<=m;j++)
for(i=1,l=1,r=0;i<=n;i++)if(!cant[i][j]){
while(l<=r&&f[pre][i][j]-i>=f[pre][dl[r]][j]-dl[r])r--;
dl[++r]=i;
while(l<r&&i-dl[l]>len)l++;
f[now][i][j]=f[pre][dl[l]][j]-dl[l]+i;
}else l=1,r=0;
}else
if(dir==1){
for(j=1;j<=m;j++)
for(i=n,l=1,r=0;i;i--)if(!cant[i][j]){
while(l<=r&&f[pre][i][j]+i>=f[pre][dl[r]][j]+dl[r])r--;
dl[++r]=i;
while(l<r&&dl[l]-i>len)l++;
f[now][i][j]=f[pre][dl[l]][j]+dl[l]-i;
}else l=1,r=0;
}
//    for(i=1;i<=n;puts(""),i++)for(j=1;j<=m;j++)printf("  %d",f[now][i][j]);
}

int main(){
register int i,j;
n=read(),m=read(),sx=read(),sy=read(),K=read();
for(i=1;i<=n;i++){
for(rx=getchar();rx!='.'&&rx!='x';rx=getchar());cant[i][1]=rx=='x';
for(j=2;j<=m;j++)cant[i][j]=getchar()=='x';
}

for(i=1;i<=n;i++)memset(f[0][i],195,(m+1)<<2);
f[0][sx][sy]=0;
now=1,pre=0;
while(K--){
j=read(),len=read()-j+1,dir=read(),
dp(dir);swap(now,pre);
}
for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(f[pre][i][j]>ans)ans=f[pre][i][j];
printf("%d\n",ans);
return 0;
}


View Code
  因为每种方向都写了一发所以比较长(虽然是复制粘贴的= =)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: