zoukankan      html  css  js  c++  java
  • luogu P3800 Power收集

    二次联通门 : luogu P3800 Power收集

    /*
        luogu P3800 Power收集
        
        
        一眼看出dp方程
        
        dp[i][j] = dp[i][k] + map[i][j] k∈ [j - T, j + T];
        
        一眼知道是单纯dp过不了 
        考虑优化
        之前都是用线段树水
        这次明显不行了
        N * M *log 
        再带上大常数。。。
         
        所以用单调队列优化
        单调队列维护滑动区间最大值 
         
    */
    #include <cstdio>
    
    #define Max 4009
    
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word < '0' || word > '9')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
    
    int map[Max][Max];
    int dp[Max][Max];
    
    int N, M, K, T;
    inline int min (int a, int b)
    {
        return a < b ? a : b;
    }
    
    inline int max (int a, int b)
    {
        return a > b ? a : b;
    }
    
    struct Queue_Data
    {
        int __queue[Max];
        
        int Head, Tail;
        
        void Clear ()
        {
            for (int i = 1; i <= Tail; i ++)
                __queue[i] = 0;
            
            Head = 1;
            Tail = 0;
        }
        
        inline void Push (int x)
        {
            __queue[++ Tail] = x;
        }
        
        inline void Pop (int i, int pos)
        {
            for (; Head <= Tail && dp[i - 1][pos] >= dp[i - 1][this->back ()]; Tail --);
        }
        
        inline int front ()
        {
            return __queue[Head];
        }    
        
        inline int back ()
        {
            return __queue[Tail];
        }
    };
    
    Queue_Data Queue;
     
    int main (int argc, char *argv[])
    {
        
        read (N);
        read (M);
        read (K);
        read (T);
        
        for (int x, y, z; K --; map[x][y] = z)
        {
            read (x);
            read (y);
            read (z);
        }
        
        for (int i = 1; i <= M; i ++)
            dp[1][i] = map[1][i];
            
        register int R = min (T + 1, M);
        
        for (register int i = 2; i <= N; i ++)
        {    
            Queue.Clear ();
            
            for (register int j = 1; j <= R; j ++)
            {
                Queue.Pop (i, j);
                Queue.Push (j); 
            }
            
            for (register int j = 1; j <= M; j ++)
            {
                if (j + T <= M)
                {
                    Queue.Pop (i, j + T);
                    Queue.Push (j + T); 
                }
                
                if (Queue.front () < j - T)
                    Queue.Head ++;
                dp[i][j] = dp[i - 1][Queue.front ()] + map[i][j];
                
            }
        } 
        int Answer = 0;
        
        for (int i = 1; i <= N; i ++)
            Answer = max (Answer, dp[N][i]);
        
        printf ("%d", Answer); 
        return 0;
    }
  • 相关阅读:
    编译原理词/语法分析
    【转】 c# 中为何load事件中不能画图
    [原创]GAMITGLOBK数据处理报告
    Google Earth上的点标记
    序贯平差
    【原创】C#写的水准网平差程序
    楼梯问题:一次最多跨两个阶梯,有多少种走法
    springMVC + Dubbo + zooKeeper超详细 步骤
    Git(to be continued...)
    autoconf & automake
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/7077776.html
Copyright © 2011-2022 走看看