[bzoj1499] [NOI2005]瑰丽华尔兹
2016-02-13 11:18
253 查看
单调队列优化。。。f[k][i][j]表示k个时间段过后,走到点(i,j)时,最多已走过了多少个格子。
因为每个时间段内的方向都是一样的,所以用单调队列优化一下就好了。。。
这题其实就是个多重背包。。一段时间段的长度就是背包容量,而点(i,j)往某个方向最多能走多少格就是物品的数目,物品价值都为1.。所以抛开四种方向不说,这题好像比多重背包还简单点?
一开始写了一坨预处理出每个点往各个方向最大扩展长度,结果dp的时候发现似乎不用?。。。如果当前点为障碍点的话直接把单调队列清空就好了QAQ
View Code
因为每种方向都写了一发所以比较长(虽然是复制粘贴的= =)
因为每个时间段内的方向都是一样的,所以用单调队列优化一下就好了。。。
这题其实就是个多重背包。。一段时间段的长度就是背包容量,而点(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
因为每种方向都写了一发所以比较长(虽然是复制粘贴的= =)
相关文章推荐
- 最小生成树prim、
- 转换函数
- 冥想
- OC-NSString从文件中读取字符串
- 《计算机硬件体系及IO优化》
- POJ 3468_A Simple Problem with Integers(线段树)
- POJ 3468_A Simple Problem with Integers(线段树)
- 【C语言】C语言常量和变量
- 【C语言】C语言常量和变量
- Rapid IO接口
- 一个简单的弹出对话框的shellcode(取自0day2一书)
- usaco 1.4.1 ariprog
- 【翻译自mos文章】在Oracle 12c中建立用户--避免ORA-65096 or ORA-65049错误
- java基础学习笔记之泛型
- leetcode:Additive Number
- 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值
- SERDES总结
- android studio中做断点测试
- leetcode:Remove Invalid Parentheses
- Leetcode 118 根据行数输出杨辉三角形