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; }
myj 吊打我Orz,xxy 捆起来打我Orz,myl 文化课上天Orz, lrh 姿势水平敲高Orz, hkd 特别胖Orz%%%,cys 智商感人Orz,syl zz专业Orz,我没有学上, 我们未来一片光明