zoukankan      html  css  js  c++  java
  • [NOI2005] 瑰丽华尔兹

    [NOI2005] 瑰丽华尔兹

    [mathfrak{<<The Crave>>} ]

    题目大意:(N imes M)的矩阵,(T)个时间段,某个特定的时间段可以向一个方向滑动或不滑动,不可以撞到边界和障碍,求最长滑动距离

    Solution

    • ({f[k][i][j]})为第(i)个时间段结束时走到((i,j))的最长滑动距离,无法到达表示为(-infty),设(len=t_k-s_k+1),即第(k)个时间段的持续时间
    • (f[k][i][j]=maxlimits_{j-lenleq tleq j}(f[k-1][i][t]+j-t)=maxlimits_{j-lenleq tleq j}(f[k-1][i][t]-t)+j)(这是向右走)

    我们可以维护一个单调队列,保存(k−1)时刻的所有可行状态的(f)值与(t),保证(t)单调递增,(f)值单调递减,在(dp)到第(t)段时,首先枚举行(i),然后从左到右来枚举(j),并时刻保证队首的(t)满足限制条件j−t≤len,这样的单调队列的队首显然是最优的,用此时的队首的(f[k−1][i][t]+j-t)来更新答案。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 205;
    const int INF = 2147483644;
    const int dx[] = {0, -1, 1, 0, 0};
    const int dy[] = {0, 0, 0, -1, 1};//第一位是0 
    
    char qwq[N][N];
    
    int n, m, T, ans;
    int dp[N][N];
    
    struct Node {
    	int dp, pos;
    }q[N];//一行或一列 
    
    void solve(int x, int y, int len, int d) {
    	int head = 1, tail = 0;
    	for(int i = 1; x >= 1 && x <= n && y >= 1 && y <= m;  i++, x += dx[d], y += dy[d]) {
    		//一直朝一个方向走
    		if(qwq[x][y] == 'x') head = 1, tail = 0;//之前的都清除
    		else {
    			while(head <= tail && q[tail].dp + i - q[tail].pos < dp[x][y]) tail--;//不符合单调递减的单调队列性质 
    			q[++tail] = Node{dp[x][y], i};//入队 
    			if(q[tail].pos - q[head].pos > len) head++;//队首元素超出"max()"的范围 
    			dp[x][y] = q[head].dp + i - q[head].pos;//i-q[head].pos 就是这个时间段走的距离 
    			ans = max(ans, dp[x][y]);
    		}
    	}
    	return; 
    }
    
    int main () {
    	int sx, sy;
    	scanf("%d %d %d %d %d", &n, &m, &sx, &sy, &T);
    	for(int i = 1; i <= n; ++i)
    		scanf("%s", qwq[i] + 1);
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j) // 
    			dp[i][j] = -INF;
    	dp[sx][sy] = 0;//其他地方都是-INF 
    	for(int i = 1, s, t, d, len; i <= T; ++i) {
    		scanf("%d %d %d", &s, &t, &d);
    		len = t - s + 1;
    		if(d == 1) for(int j = 1; j <= m; ++j) solve(n, j, len, d);//向上
    		if(d == 2) for(int j = 1; j <= m; ++j) solve(1, j, len, d);//向下
    		if(d == 3) for(int j = 1; j <= n; ++j) solve(j, m, len, d);//向左
    		if(d == 4) for(int j = 1; j <= n; ++j) solve(j, 1, len, d);//向右 	
    	}
    		cout << ans << endl;		
    	return 0;
    }
    
  • 相关阅读:
    KBMMW 4.80.00 发布
    RCF库ClientStub.setAutoReconnect
    编译 boost
    2017学习计划
    _beginthreadex注意事项
    push_back模式工作
    总结2016
    <转>好婚姻是彼此放心
    ProcessExplore 最新版
    网站seo新手快速提升自己的技巧
  • 原文地址:https://www.cnblogs.com/LMSH7/p/9684632.html
Copyright © 2011-2022 走看看