• NOI 2005 瑰丽华尔兹(三维DP + 单调队列优化)


    思路:

    1. dp[k][x][y] 表示处理到第 k 个时间区间时,最终点落在 x, y 坐标上,移动的最大距离。

    3. dp[k][x][y] = max(dp[k-1][x1][y1] + delta); 由于 delta 是相对偏移量,所以对于 x/y 所在的维度可以用单调队列优化。

    4. 由于第 k - 1 次之后,无法确定第 k 步的起始位置,所以要采取枚举的办法,所以最终的时间复杂度为 O(N*M*K)

    5. 初始状态为 dp[0][x][y] = 0, 其他赋值为 -INFS,这样才能保证枚举的过程中,最终结果是在以 (x, y) 为起始点出发的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 210;
    const int INFS = 0x3fffffff;
     
    int dx[5] = {-1, 1, 0, 0};
    int dy[5] = {0, 0, -1, 1};
     
    char grid[MAXN][MAXN];
    int t1, t2, dp[2][MAXN][MAXN], deq[MAXN], pos[MAXN];
     
    void solvedp(int x, int y, int width, int size, int d)
    {
        int s = 0, e = -1;
        for (int i = 1; i <= width; ++i)
        {
            if (grid[x][y] == '.')
            {
                int val = dp[t1][x][y] - i;
                while (s <= e && deq[e] < val)
                    --e;
     
                deq[++e] = val, pos[e] = i;
                while (i - pos[s] > size)
                    ++s;
     
                dp[t2][x][y] = deq[s] + i;
            }
            else
            {
                s = 0, e = -1;
                dp[t2][x][y] = -INFS;
            }
            x += dx[d], y += dy[d];
        }
    }
     
    int main()
    {
        int N, M, x, y, K;
        while (scanf("%d %d %d %d %d", &N, &M, &x, &y, &K) != EOF)
        {
            for (int i = 1; i <= N; ++i)
                scanf("%s", &grid[i][1]);
     
            for (int i = 1; i <= N; ++i)
                for (int j = 1; j <= M; ++j)
                    dp[0][i][j] = -INFS;
            dp[0][x][y] = 0;
     
            t1 = 1, t2 = 0;
            for (int i = 0; i < K; ++i)
            {
                int si, ti, di;
                scanf("%d %d %d", &si, &ti, &di);
     
                t1 ^= 1, t2 ^= 1;
                 
                if (di == 1)
                {
                    for (int j = 1; j <= M; ++j)
                        solvedp(N, j, N, ti - si + 1, di - 1);
                }
                else if (di == 2)
                {
                    for (int j = 1; j <= M; ++j)
                        solvedp(1, j, N, ti - si + 1, di - 1);
                }
                else if (di == 3)
                {
                    for (int j = 1; j <= N; ++j)
                        solvedp(j, M, M, ti - si + 1, di - 1);
                }
                else if (di == 4)
                {
                    for (int j = 1; j <= N; ++j)
                        solvedp(j, 1, M, ti - si + 1, di - 1);
                }
            }
     
            int ans = 0;
            for (int i = 1; i <= N; ++i)
                for (int j = 1; j <= M; ++j)
                    ans = max(ans, dp[t2][i][j]);
     
            printf("%d\n", ans);
        }
        return 0;
    }
  • 相关阅读:
    微支付开发(.net)
    微信公众平台开发(一) 配置接口
    [040] 微信公众帐号开发教程第16篇-应用实例之历史上的今天
    [039] 微信公众帐号开发教程第15篇-自定义菜单的view类型(访问网页)
    [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
    [037] 微信公众帐号开发教程第13篇-图文消息全攻略
    【微网站开发】之微信内置浏览器API使用
    .Net(c#)汉字和Unicode编码互相转换
    jquery.uploadify上传文件配置详解(asp.net mvc)
    微信公众平台入门开发教程.Net(C#)框架
  • 原文地址:https://www.cnblogs.com/kedebug/p/2937861.html
Copyright © 2020-2023  润新知