[NOI2005] 瑰丽华尔兹

LYZ搬来国赛题......又是2005的!

感觉NOI2005的题都好神啊。

洛谷 P2254 传送门

DP。

设f[i][j]为走到(i,j)的最大值。时间那一维滚动掉。

对于每一个时间段,枚举开始位置,进行DP。

从每个开始位置向输入的方向进行DP,用单调队列优化一下。

遇到障碍物就要清空队列。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int n,m,sx,sy,k,ans;
 7 int ob[205][205];
 8 int dx[]={0,-1,1,0,0};
 9 int dy[]={0,0,0,-1,1};
10 int f[205][205];
11 struct data{int pos,val;}q[205];
12 int hd,tl;
13 
14 void cal(int x,int y,int len,int dir)
15 {
16     hd=1,tl=0;
17     for(int i=1;x>0&&x<=n&&y>0&&y<=m;i++,x+=dx[dir],y+=dy[dir])
18     {
19         if(ob[x][y]){hd=1,tl=0;continue;}
20         while(hd<=tl&&q[tl].val+i-q[tl].pos<f[x][y])tl--;
21         q[++tl]=(data){i,f[x][y]};
22         if(q[tl].pos-q[hd].pos>len)hd++;
23         f[x][y]=q[hd].val+i-q[hd].pos;
24         ans=max(ans,f[x][y]);
25     }
26 }
27 
28 int main()
29 {
30     scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&k);
31     for(int i=1;i<=n;i++)
32     {
33         char tmp[205];
34         scanf("%s",tmp+1);
35         for(int j=1;j<=m;j++)
36             if(tmp[j]=='x')ob[i][j]=1;
37     }
38     memset(f,0xf3,sizeof(f));
39     f[sx][sy]=0;
40     for(int i=1;i<=k;i++)
41     {
42         int st,ed,dir;
43         scanf("%d%d%d",&st,&ed,&dir);
44         int len=ed-st+1;
45         if(dir==1)for(int j=1;j<=m;j++)cal(n,j,len,dir);
46         if(dir==2)for(int j=1;j<=m;j++)cal(1,j,len,dir);
47         if(dir==3)for(int j=1;j<=n;j++)cal(j,m,len,dir);
48         if(dir==4)for(int j=1;j<=n;j++)cal(j,1,len,dir);
49     }
50     printf("%d",ans);
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9746914.html