zoukankan      html  css  js  c++  java
  • LA 4327 Parade(单调队列优化dp)

    题目链接:

    题目大意(摘自刘汝佳<<算法竞赛入门经典--训练指南>>):F城是由n+1条横向路和m+1条竖向路组成。你的任务是从最南边的路走到最北边的路,使得走过的路上的高兴值和最大(注意,一段路上的高兴值可能是负数)。同一段路不能经过两次,且不能从北往南走,另外,在每条横向路上所花的时间不能超过k。求从南到北走完可以获得的最大高兴值。

    分析:用dp[i][j]表示到达编号为(i,j)的路口时所能得到的最大高兴值,则dp[i][j] = max{ dp[i+1][j]; dp[i+1][k] + s[i+1][j]-s[i+1][k], (L[i][j] <= k < j); dp[i+1][k] + s[i+1][k]-s[i+1][j], (j <= k < R[i][j]) };

    其中,s[i][j] 表示第i行从第0个路口到第j个路口的高兴值之和,L[i][j]是同一行上能够走到(i,j)位置的最左位置,R[i][j]是同一行上能够走到(i,j)位置的最右位置,这三个量都可以预处理出来。

    上述dp的复杂度是O(n^3)的,需要优化,考虑dp[i][j] = max(dp[i+1][k] + s[i+1][j]-s[i+1][k]),i,j固定时,s[i+1][j]为常量,不妨设s[i+1][j] = P, 且令f[k] = dp[i+1][k] - s[i+1][k],则dp[i][j] = max(f[k]) + P,此时就可以用单调队列来维护了,对于每行,从左到右扫描,并维护一个递减的单调对列。具体参看代码。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define N 104
    #define M 10004
    
    int L[N][M], R[N][M];
    int v[N][M], t[N][M];
    int n, m, k;
    int Q[M];
    int f[M], sum[N][M], dp[N][M];
    int main()
    {
        while(~scanf("%d %d %d", &n, &m, &k), n||m||k)
        {
            for(int i = 1; i <= n+1; i++)
                for(int j = 0; j < m; j++)
                    scanf("%d", &v[i][j]);
            for(int i = 1; i <= n+1; i++)
                for(int j = 0; j < m; j++)
                    scanf("%d", &t[i][j]);
            for(int i = 1; i <= n+1; i++)
            {
                sum[i][0] = 0;
                for(int j = 1; j <= m; j++) sum[i][j] = sum[i][j-1] + v[i][j-1];
            }
            for(int i = 1; i <= n+1; i++)
            {
                L[i][0] = 0, R[i][m] = m;
                int cur = 0, id = 0;
                for(int j = 1; j <= m; j++){
                    cur += t[i][j-1];
                    while(cur > k) cur -= t[i][id++];
                    L[i][j] = id;
                }
                cur = 0, id = m-1;
                for(int j = m-1; j >= 0; j--){
                    cur += t[i][j];
                    while(cur > k) cur -= t[i][id--];
                    R[i][j] = id+1;
                }
            }
            
            for(int i = 0; i < m+1; i++) dp[n+1][i] = 0;
            for(int i = n; i >= 0; i--)
            {
                int head = 0, rear = 0;
                for(int j = 0; j < m+1; j++)
                {
                    f[j] = dp[i+1][j] - sum[i+1][j];
                    while(rear < head && Q[rear] < L[i+1][j]) rear++;
                    while(head > rear && f[j] >= f[Q[head-1]]) head--;
                    Q[head++] = j;
                    dp[i][j] = max(dp[i+1][j], sum[i+1][j]+f[Q[rear]]);
                }
                head = 0, rear = 0;
                for(int j = m; j >= 0; j--)
                {
                    f[j] = dp[i+1][j] + sum[i+1][j];
                    while(rear < head && Q[rear] > R[i+1][j]) rear++;
                    while(head > rear && f[j] >= f[Q[head-1]]) head--;
                    Q[head++] = j;
                    dp[i][j] = max(dp[i][j], f[Q[rear]]-sum[i+1][j]);
                }
            }
            int ans = 0;
            for(int i = 0 ; i < m+1; i++) ans = max(ans, dp[0][i]);
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    风讯DotNetCMS sp5安装笔记
    datalist中实现自动编号写法
    windows server 2008 自动登录设置
    C#软件监控外部程序运行状态
    WPF启动屏幕SplashScreen
    Windows Server 2019 在桌面上显示“我的电脑”
    使用jquery的load方法加载html页面,html引入的js无效
    sql查询文章上一篇下一篇
    C#调用user32.dll Win32的API函数
    C#调用dll提示"试图加载格式不正确的程序
  • 原文地址:https://www.cnblogs.com/beisong/p/4755797.html
Copyright © 2011-2022 走看看