zoukankan      html  css  js  c++  java
  • [NOI2005]瑰丽华尔兹-单调队列优化DP

    https://www.luogu.com.cn/problem/P2254

    给你一张地图,一些地方不能走,输入初始位置,(K)段时间,每段时间内要么只能往指定的方向走,要么不走,问最远能走多长的路径。(n,m,kleq 200)

    (f[i][j][k])表示第(k)段时间走完之后在((i,j))处的答案,暴力转移(egin{aligned}f[i][j][k]=max_{t=0}^{ed_k-st_k+1}{f[i-tDelta x][j-tDelta y][k-1]+t}end{aligned}),这样就得到了一个四次方的DP,但是应该是数据太水(以及可能因为是十几年前的题了,当时测评机没这么快)…这么个大暴力就过了这题:

    rep(k,1,K)rep(i,1,n)rep(j,1,m)if(avl[i][j]){
        int mx=-INF;
        rep(t,0,ed[k]-st[k]+1){
            int cx=i-t*di[d[k]],cy=j-t*dj[d[k]];
            if(!check(cx,cy))break;
            if(f[cx][cy][k-1]==-INF)continue;
            mx=max(mx,f[cx][cy][k-1]+t);
        }
        f[i][j][k]=mx;
    }
    

    不过还是来优化转移过程,其实(Delta x,Delta y)里面会有一个是0,假设(j)定下来,(i)是这次动的方向,我们对于每个确定的(k,j),其实可以(O(n))

    (f[i][j][k]=max_{t=0}^{len}{f[i-tDelta x][j][k-1]+t})进行转移:假设这个(d[k])意味着(i)只能增大,那我就从1枚举(i),用单调队列维护(f[i-tDelta x][j][k-1]-t),每次再用(Q.front()+t)来更新答案(注意前面单调队列里维护的是(-t),因为原来dp式子里的(t)的含义其实是两个位置的距离,相当于是(t_{当前}-t_{从哪转移来})

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<double,int> pdi;
    typedef vector<int> vi;
    const int N=205;
    const int INF=(~0u>>2);
    struct Queue
    {
    	int x[N],y[N],s[N],st,ed;
    	void clear(){st=1;ed=0;}
    	void push_back(int a,int b,int v){ed++;x[ed]=a;y[ed]=b;s[ed]=v;}
    	void pop_back(){ed--;}
    	void pop_front(){st++;}
    	bool empty(){return st>ed;}
    }Q;
    int n,m,K,t,sx,sy;
    int st[N],ed[N],d[N],f[N][N][N];
    int di[]={0,-1,1,0,0},dj[]={0,0,0,-1,1};
    bool avl[N][N];
    char str[N];
    
    bool inside(int x,int y){return (1<=x&&x<=n&&1<=y&&y<=m);}
    bool check(int x,int y){return (avl[x][y]&&inside(x,y));}
    bool in_range(int x1,int y1,int x2,int y2,int d)
    {
    	return (abs(x1-x2)<=d&&abs(y1-y2)<=d);
    }
    void solve(int x,int y,int len,int d,int k)
    {
    	int t=0;Q.clear();
    	while(inside(x,y))
    	{
    		if(check(x,y))
    		{
    			while(!Q.empty())
    			{
    				int qx=Q.x[Q.st],qy=Q.y[Q.st];
    				if(in_range(qx,qy,x,y,len))break;
    				else Q.pop_front();
    			}
    			while(!Q.empty()&&Q.s[Q.ed]<=f[x][y][k-1]-t)
    				Q.pop_back();
    			if(f[x][y][k-1]!=-INF)
    				Q.push_back(x,y,f[x][y][k-1]-t);
    				
    			if(!Q.empty())f[x][y][k]=Q.s[Q.st]+t;
    		}else
    		{
    			while(!Q.empty())Q.pop_front();
    		}
    		t++;
    		x+=di[d];y+=dj[d];
    	}
    }
    int main()
    {
    	scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&K);
    	rep(i,1,n)
    	{
    		scanf("%s",str+1);
    		rep(j,1,m)if(str[j]=='.')avl[i][j]=1;
    	}
    	rep(i,1,K)scanf("%d%d%d",&st[i],&ed[i],&d[i]);
    	rep(i,1,n)rep(j,1,m)rep(k,0,K)f[i][j][k]=-INF;
    	f[sx][sy][0]=0;
    	rep(k,1,K)
    	{
    		int len=ed[k]-st[k]+1;
    		if(d[k]==1)rep(j,1,m)solve(n,j,len,d[k],k);
    		if(d[k]==2)rep(j,1,m)solve(1,j,len,d[k],k);
    		if(d[k]==3)rep(i,1,n)solve(i,m,len,d[k],k);
    		if(d[k]==4)rep(i,1,n)solve(i,1,len,d[k],k);
    	}
    	int ret=-INF;
    	rep(i,1,n)rep(j,1,m)if(avl[i][j])ret=max(ret,f[i][j][K]);
    	printf("%d",ret);
    	return 0;
    }
    
  • 相关阅读:
    学习WindowsPhone 2013/12/22
    spring-aop学习
    easymock+junit+spring学习·
    javaWeb实现文件上传与下载 (转)
    Java实现视频网站的视频上传、视频转码、视频关键帧抽图, 及视频播放功能
    jsp自定义标签
    listener监听器
    移植一个项目到本地的问题
    struts1拦截器
    eclipse开发 javafx(转)
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/14658212.html
Copyright © 2011-2022 走看看