zoukankan      html  css  js  c++  java
  • [bzoj1499] [NOI2005]瑰丽华尔兹

      单调队列优化。。。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  
    View Code

      因为每种方向都写了一发所以比较长(虽然是复制粘贴的= =)

  • 相关阅读:
    修改RedHat7的root用户密码
    Linux目录,rpm及top,vi命令简记
    Centos7或RedHat7下安装Mysql
    异常、线程
    File类
    JDBC的学习(一)
    MySql多表查询_事务_DCL(资料三)
    MySql约束_设计_备份还原(资料二)
    MySql基础_DDL_DML_DQL(资料一)
    算法小结(一)
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5187498.html
Copyright © 2011-2022 走看看