• 【Luogu P2254】[NOI2005] 瑰丽华尔兹


    链接:

    题目

    题目大意:

    一个 (n imes m) 的棋盘,有一些格子里有障碍,你在点 ((x,y)),在 (K) 段时间内指定你的方向,你可以不走,求出你最多能走多远。

    正文:

    考虑用动态规划。设 (f_{t,x,y}) 表示第 (t) 时刻你在 ((x,y)) 的最大路程,则有:

    [f_{t,x,y}=left{egin{matrix}max{f_{t-1,x-1,y} + 1,f_{t,x,y}}&(d=1)\max{f_{t-1,x+1,y} + 1,f_{t,x,y}}&(d=2)\max{f_{t-1,x,y-1} + 1,f_{t,x,y}}&(d=3)\max{f_{t-1,x,y+1} + 1,f_{t,x,y}}&(d=4)end{matrix} ight. ]

    但是因为 (t) 太大了,不管怎么优化都会超时,所以我们不能用这个状态那么设 (f_{K,x,y}) 表示第 (K) 时段你在 ((x,y)) 的最大路程,则有:

    [f_{K,x,y}=left{egin{matrix}max_{kleq t_K-s_K+1}{f_{K-1,x-k,y} + k,f_{K,x,y}}&(d=1)\max_{kleq t_K-s_K+1}{f_{K-1,x+k,y} + k,f_{K,x,y}}&(d=2)\max_{kleq t_K-s_K+1}{f_{K-1,x,y-k} + k,f_{K,x,y}}&(d=3)\max_{kleq t_K-s_K+1}{f_{K-1,x,y+k} + k,f_{K,x,y}}&(d=4)end{matrix} ight. ]

    就可以用单调队列优化它了,又因为转移只包括了相邻项,所以 (K) 被滚动掉。

    代码:

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ZYC using
    #define AK namespace
    #define IOI std
    #define ll long long
    
    ZYC AK IOI;
    
    const int N = 210;
    
    int n, m, x, y, K; 
    int s, t, d;
    int a[N][N], ans;
    int f[N][N], head, tail;
    
    struct node
    {
    	int val, i;
    } q[N * N];
    
    int dx[5] = {0, -1, 1, 0, 0},
    	dy[5] = {0, 0, 0, -1, 1};
    
    void Solve(int x, int y, int d, int len)
    {
    	head = 1, tail = 0;
    	for (int i = 1; x >= 1 && x <= n && y >= 1 && y <= m; i ++, x += dx[d], y += dy[d])
    		if (a[x][y]) head = 1, tail = 0;
    		else 
    		{
    			while (head <= tail && q[tail].val + i - q[tail].i < f[x][y]) tail--;
    			q[++tail] = (node) {f[x][y], i};
    			while (head <= tail && i - q[head].i > len) head++;
    			f[x][y] = q[head].val + i - q[head].i;
    			ans = max(ans, f[x][y]); 
    		}
    } 
    
    int main()
    {
    //	freopen(".in", "r", stdin);
    //	freopen(".out", "w", stdout);
    	memset (f, -127 / 3, sizeof f);
    	scanf ("%d%d%d%d%d", &n, &m, &x, &y, &K);
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= m; j++)
    		{
    			char c = getchar();
    			while (c != '.' && c != 'x') c = getchar();
    			if (c == '.') a[i][j] = 0;
    			else a[i][j] = 1;
    		}
    	f[x][y] = 0;
    	for (int k = 1; k <= K; k++)
    	{
    		scanf ("%d%d%d", &s, &t, &d);
    		if (d == 1) for (int i = 1; i <= m; i++) Solve(n, i, d, t - s + 1);
    		if (d == 2) for (int i = 1; i <= m; i++) Solve(1, i, d, t - s + 1);
    		if (d == 3) for (int i = 1; i <= n; i++) Solve(i, m, d, t - s + 1);
    		if (d == 4) for (int i = 1; i <= n; i++) Solve(i, 1, d, t - s + 1);
    	}
    	printf ("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    201871010106丁宣元 《面向对象程序设计(java)》第八周学习总结
    201871010106丁宣元 《面向对象程序设计(java)》第十一周学习总结
    201871010106丁宣元 《面向对象程序设计(java)》第十周学习总结
    学习:数据结构树状数组
    学习:数据结构线段树
    学习:数据结构哈希
    学习:数据结构单调栈
    学习:数学欧拉定理与扩展欧拉定理
    CRUD全栈式编程架构之导入导出的设计
    CRUD全栈式编程架构之服务层的设计
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14402086.html
Copyright © 2020-2023  润新知