标签:
http://acm.hdu.edu.cn/showproblem.php?pid=4374
3 3 2 1 7 8 1 4 5 6 1 2 3
29
/** hdu 4374 单调队列+dp 题目大意:一个n层的楼,每层楼有m个格子,每个格子有一定的价值。在每一层楼只能向一个方向走最多走t步, 开始在顶层的x位置,问到底层的路线上能得到的价值最大。 解题思路:从下往上走,每个状态dp[i][j]为从i层j格子到底层所能得到的最大价值。 用sum[i][j]表示第i层前j格子的和。 从左边到j位置的状态转移方程 dp[i][j]=max(dp[i+1][k]+sum[i][j]-sum[i][k-1]);(k+t<=j)。 上式即为:dp[i][j]=max(dp[i+1][k]-sum[i][k-1])+sum[i][j+1]; 由于max里面包含的项都已知切与j无关。故可以用单调队列,维护单调递增即可。 其右边的状态转移方程为dp[i][j]=max(dp[i+1][k]+sum[i][k])-sum[i][j-1];(k-t>=j) */ #include <stdio.h> #include <string.h> #include <iostream> using namespace std; int n,m,x,t,a[105][10005],dp[105][10005],sum[105][10005]; int q[10005],front,rear,ans_l[10005],ans_r[10005]; int main() { while(~scanf("%d%d%d%d",&n,&m,&x,&t)) { memset(dp,0,sizeof(dp)); memset(sum,0,sizeof(sum)); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { scanf("%d",&a[i][j]); sum[i][j]=sum[i][j-1]+a[i][j]; } } for(int i=n; i>=1; i--) { front=0; rear=0; q[rear++]=1; ans_l[1]=1; for(int j=2; j<=m; j++) { while(front<rear&&dp[i+1][q[rear-1]]-sum[i][q[rear-1]-1]<=dp[i+1][j]-sum[i][j-1]) { rear--; } q[rear++]=j; if(q[front]+t<j) front++; ans_l[j]=q[front]; } front=0; rear=0; q[rear++]=m; ans_r[m]=m; for(int j=m-1; j>=1; j--) { while(front<rear&&dp[i+1][q[rear-1]]+sum[i][q[rear-1]]<=dp[i+1][j]+sum[i][j]) { rear--; } q[rear++]=j; if(q[front]-t>j) front++; ans_r[j]=q[front]; } int t1,t2; for(int j=1; j<=m; j++) { t1=dp[i+1][ans_l[j]]+sum[i][j]-sum[i][ans_l[j]-1]; t2=dp[i+1][ans_r[j]]+sum[i][ans_r[j]]-sum[i][j-1]; dp[i][j]=max(t1,t2); } } printf("%d\n",dp[1][x]); } return 0; }
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/43669373