zoukankan      html  css  js  c++  java
  • bzoj 1499: [NOI2005]瑰丽华尔兹【dp+单调队列】

    设f[a][i][j]为第a段时间结束时在(i,j)位置的最长滑行距离,转移很好想,就是分四个方向讨论,然后枚举这段时间的滑行长度取个max即可
    但是这样是O(n^4)的,考虑优化
    发现同一行或列,取max对应a-1中的是单调挪动的一个区间,所以用单调栈维护当前区间,每次移动的时候要把左端点已经大于最长滑行距离的出队,然后把新点放进去,然后直接更新答案,这样就省去了一个n的时间
    注意如果遇到障碍的话,当前的f赋值-inf,然后把队列清空

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=205,dx[]={0,-1,1,0,0},dy[]={0,0,0,-1,1},inf=1e9;
    int n,m,k,sx,sy,s[N],t[N],d[N],f[N][N][N],q[N],l,r,ans;
    char c[N][N];
    int main()
    {
    	scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&k);
    	for(int i=1;i<=n;i++)
    		scanf("%s",c[i]+1);
    	for(int i=1;i<=k;i++)
    		scanf("%d%d%d",&s[i],&t[i],&d[i]);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			f[0][i][j]=-inf;
    	f[0][sx][sy]=0;
    	for(int a=1;a<=k;a++)
    	{
    		if(d[a]==1)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				l=1,r=0;
    				for(int i=n;i>=1;i--)
    				{
    					if(c[i][j]=='x')
    					{
    						l=1,r=0;
    						f[a][i][j]=-inf;
    						continue;
    					}
    					while(l<=r&&q[l]-i>t[a]-s[a]+1)
    						l++;
    					while(l<=r&&f[a-1][i][j]+i>f[a-1][q[r]][j]+q[r])
    						r--;
    					q[++r]=i;
    					f[a][i][j]=f[a-1][q[l]][j]+q[l]-i;
    				}
    			}
    		}
    		if(d[a]==2)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				l=1,r=0;
    				for(int i=1;i<=n;i++)
    				{
    					if(c[i][j]=='x')
    					{
    						l=1,r=0;
    						f[a][i][j]=-inf;
    						continue;
    					}
    					while(l<=r&&i-q[l]>t[a]-s[a]+1)
    						l++;
    					while(l<=r&&f[a-1][i][j]-i>f[a-1][q[r]][j]-q[r])
    						r--;
    					q[++r]=i;
    					f[a][i][j]=f[a-1][q[l]][j]+i-q[l];
    				}
    			}
    		}
    		if(d[a]==3)
    		{
    			for(int i=1;i<=n;i++)
    			{
    				l=1,r=0;
    				for(int j=m;j>=1;j--)
    				{
    					if(c[i][j]=='x')
    					{
    						l=1,r=0;
    						f[a][i][j]=-inf;
    						continue;
    					}
    					while(l<=r&&q[l]-j>t[a]-s[a]+1)
    						l++;
    					while(l<=r&&f[a-1][i][j]+j>f[a-1][i][q[r]]+q[r])
    						r--;
    					q[++r]=j;//cerr<<i<<" "<<j<<" "<<q[l]<<"   "<<f[a-1][i][j]+j<<" "<<f[a-1][i][q[l]]+q[l]<<endl;
    					f[a][i][j]=f[a-1][i][q[l]]+q[l]-j;
    				}
    			}
    		}
    		if(d[a]==4)
    		{
    			for(int i=1;i<=n;i++)
    			{
    				l=1,r=0;
    				for(int j=1;j<=m;j++)
    				{
    					if(c[i][j]=='x')
    					{
    						l=1,r=0;
    						f[a][i][j]=-inf;
    						continue;
    					}
    					while(l<=r&&j-q[l]>t[a]-s[a]+1)
    						l++;
    					while(l<=r&&f[a-1][i][j]-j>f[a-1][i][q[r]]-q[r])
    						r--;
    					q[++r]=j;//cerr<<i<<" "<<j<<" "<<q[l]<<endl;
    					f[a][i][j]=f[a-1][i][q[l]]+j-q[l];
    				}
    			}
    		}
    		// for(int i=1;i<=n;i++)
    		// {
    			// for(int j=1;j<=m;j++)
    				// cerr<<f[a][i][j]<<" ";
    			// cerr<<endl;
    		// }
    		// cerr<<endl;
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			ans=max(ans,f[k][i][j]);
    	printf("%d
    ",ans);
    	return 0;
    }
    /*
    10 10 5 8 5
    ..........
    ......xxxx
    .....xxxxx
    .....xxxxx
    ..........
    xxxx......
    ..........
    ..........
    ..........
    ..x.......
    1 5 3
    6 7 1
    8 11 2
    12 15 3
    16 17 2
    */
    
  • 相关阅读:
    HTML5 <input> multiple 属性
    AWS
    new Set() 数组去重
    IAM
    Amazon S3
    Promis 实例
    JS
    React 5
    React 4
    React 3
  • 原文地址:https://www.cnblogs.com/lokiii/p/9614852.html
Copyright © 2011-2022 走看看