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;
    }
    
  • 相关阅读:
    085 Maximal Rectangle 最大矩形
    084 Largest Rectangle in Histogram 柱状图中最大的矩形
    083 Remove Duplicates from Sorted List 有序链表中删除重复的结点
    082 Remove Duplicates from Sorted List II 有序的链表删除重复的结点 II
    081 Search in Rotated Sorted Array II 搜索旋转排序数组 ||
    080 Remove Duplicates from Sorted Array II 从排序阵列中删除重复 II
    079 Word Search 单词搜索
    078 Subsets 子集
    bzoj2326: [HNOI2011]数学作业
    bzoj2152: 聪聪可可
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/14658212.html
Copyright © 2011-2022 走看看