zoukankan      html  css  js  c++  java
  • Suspenseful

    好吧 我说句大实话

    老师真的很好看...那手qwqqqqqqq

    P2254 [NOI2005]瑰丽华尔兹

    不妨认为舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地。钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅,否则会损坏钢琴和家具,引来难缠的船长。每个时刻,钢琴都会随着船体倾斜的方向向相邻的方格滑动一格,相邻的方格可以是向东、向西、向南或向北的。而艾米丽可以选择施魔法或不施魔法:如果不施魔法,则钢琴会滑动;如果施魔法,则钢琴会原地不动。

    艾米丽是个天使,她知道每段时间的船体的倾斜情况。她想使钢琴在舞厅里滑行的路程尽量长,这样1900 会非常高兴,同时也有利于治疗托尼的晕船。但艾米丽还太小,不会算,所以希望你能帮助她。

    输入输出格式

    输入格式:

    输入文件的第一行包含5个数N, M, x, y和K。N和M描述舞厅的大小,x和y为钢琴的初始位置;我们对船体倾斜情况是按时间的区间来描述的,且从1开始计算时间,比如“在[1, 3]时间里向东倾斜,[4, 5]时间里向北倾斜”,因此这里的K表示区间的数目。

    以下N行,每行M个字符,描述舞厅里的家具。第i 行第j 列的字符若为‘ . ’,则表示该位置是空地;若为‘ x ’,则表示有家具。

    以下K行,顺序描述K个时间区间,格式为:si ti di(1 ≤ i ≤ K)。表示在时间区间[si, ti]内,船体都是向di方向倾斜的。di为1, 2, 3, 4中的一个,依次表示北、南、西、东(分别对应矩阵中的上、下、左、右)。输入保证区间是连续的,即

    s1 = 1 ti = si-1 + 1 (1 < i ≤ K)

    tK = T

    输出格式:

    输出文件仅有1行,包含一个整数,表示钢琴滑行的最长距离(即格子数)。

    (解释会发在代码里QAQ

    (这题我就是给洛谷题解加一个解释 这样以后方便罢了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 205
    using namespace std;
    int n, m, sx, sy, K, ans, dp[MAXN][MAXN];
    int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1}; 
    struct node{int dp, pos;}q[MAXN]; //q为单调递减队列,要存位置信息用来计算共走了几步 
    char map[MAXN][MAXN];
    void work(int x, int y, int len, int d) //第k个区间的时长为len,方向为d,起点坐标x,y 
    {
        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(map[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++; //队列长度超过len时队首弹出 
                dp[x][y] = q[head].dp + i - q[head].pos; //最优解是队首元素+移动距离 
                ans = max(ans, dp[x][y]); //记录结果 
            }
    }
    int main()
    {
        scanf("%d%d%d%d%d", &n, &m, &sx, &sy, &K);
        for(int i = 1; i <= n; i++) scanf("%s", map[i] + 1);
        memset(dp, 0xf3, sizeof(dp));
        dp[sx][sy] = 0; //初始化,只有初始位置是0,其他都是负无穷
        for(int k = 1, s, t, d, len; k <= K; k++)
        {
            scanf("%d%d%d", &s, &t, &d);
            len = t - s + 1;
            if(d == 1) for(int i = 1; i <= m; i++) work(n, i, len, d);//因为是向上走 所以要从后向前走
            if(d == 2) for(int i = 1; i <= m; i++) work(1, i, len, d);//其他也一样
            if(d == 3) for(int i = 1; i <= n; i++) work(i, m, len, d);
            if(d == 4) for(int i = 1; i <= n; i++) work(i, 1, len, d);
        }
        printf("%d", ans);
        return 0;
    }

    f(i,x,y)f(i,x,y)表示第i个区间(区间长设为L)后,钢琴处于(x,y)(x,y)的最大滑行距离

    假如这个区间方向是向下,则f(i1,j,y)+(xj)>f(i,x,y)(xL<=j<=x)f(i−1,j,y)+(x−j)−>f(i,x,y)(x−L<=j<=x)

    即这个区间的转移是一列一列的,每一列用一下单调队列优化dp即可

    悄悄拿来hzwer的解答qwqqqqq

  • 相关阅读:
    手动创建分区以及软硬raid的问题
    实用小工具:VNC的安装
    安装使用xen虚拟化工具
    使用vsftp与shell实现对进程与服务状态的监控
    windows server2008下搭建ftp服务
    业界虚拟化技术分析
    Android命名规范(自定义)
    Android Paint和Color类
    Android 应用中十大常见 UX 错误
    漫谈互联网产品设计之人性的弱点,你躺枪了木有?
  • 原文地址:https://www.cnblogs.com/Grigory/p/10344188.html
Copyright © 2011-2022 走看看