[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\n",ans);
79     return 0;
80 }
81  
View Code

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

 

你可能感兴趣的:([bzoj1499] [NOI2005]瑰丽华尔兹)