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;
}

 

posted @ 2017-06-25 20:16  ZlycerQan  阅读(195)  评论(0编辑  收藏  举报