hdu 4374
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4374
题意:有n层,每层有m个模块,每个模块都有对应的权值,每层只能沿一个方向走,每层最多走t步,求最大权值的和。
mark:单调队列,dp[i][j]代表第i层,第j块最大的权值。
首先每次求得dp[i][j]后,先向下走给dp[i+1][j]一个初始值,即dp[i+1][j] = dp[i][j]+w[i+1][j],(w[i][j]表示第i层第j块的权值。)
然后单调队列,左边右边各弄一次,去最大值。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> const int N = 110; const int M = 10010; int n,m,x,t; int w[N][M],sum[N][M],dp[N][M]; int s1[M],s2[M]; int q[M],fr,la; int max(int a, int b) {return a > b ? a : b;} void left(int i) { int j; for(j = 1; j <= m; j++) s1[j] = -10000000; fr = la = 0; q[la++] = 1; s1[1] = dp[i][1]; for(j = 2; j <= m; j++) { if(j-q[fr] > t) fr += j-q[fr]-t; while(fr != la && dp[i][j] >= dp[i][q[la-1]]+sum[i][j]-sum[i][q[la-1]]) la--; q[la++] = j; s1[j] = dp[i][q[fr]]+sum[i][j]-sum[i][q[fr]]; } } void right(int i) { int j; for(j = 1; j <= m; j++) s2[j] = -10000000; fr = la = 0; q[la++] = m; s2[m] = dp[i][m]; for(j = m; j > 0; j--) { if(q[fr]-j > t) fr += q[fr]-j-t; while(fr != la && dp[i][j] >= dp[i][q[la-1]]+sum[i][q[la-1]-1]-sum[i][j-1]) la--; q[la++] = j; s2[j] = dp[i][q[fr]]+sum[i][q[fr]-1]-sum[i][j-1]; } } void solve() { int i,j,k; int sum1; sum1 = 0; for(i = x; i > 0 && i >= x-t; i--) { sum1 += w[1][i]; dp[1][i] = sum1; dp[2][i] = dp[1][i]+w[2][i]; } sum1 = w[1][x]; for(i = x+1; i <= m && i <= x+t; i++) { sum1 += w[1][i]; dp[1][i] = sum1; dp[2][i] = dp[1][i]+w[2][i]; } for(i = 2; i <= n; i++) { left(i); right(i); for(j = 1; j <= m; j++) { dp[i][j] = max(s1[j], s2[j]); dp[i+1][j] = dp[i][j]+w[i+1][j]; } } } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int i,j; while(~scanf("%d%d%d%d", &n, &m, &x, &t)) { for(i = 0; i < n; i++) for(j = 0; j <= m; j++) dp[i][j] = -10000000; for(i = 0; i < N; i++) sum[i][0] = 0; for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) { scanf("%d", &w[i][j]); sum[i][j] = w[i][j]+sum[i][j-1]; } solve(); int max1 = -10000000; for(i = 1; i <= m; i++) max1 = max(max1, dp[n][i]); printf("%d\n", max1); } return 0; }