容易想到dp[i][j]表示在第i行j个路口的开始走最大高兴值。
每次可以向左走,或者向右边走,然后向北走。(或者直接往北)
向左走到,状态转移为dp[i][j] = dp[i][k] + happy[i][k][j](为了方便处理,i从1开始编号,0行dp值存0)
处理出前缀和,happy[i][k][j]表示为sum[i][j] - sum[i][k]
向左走应该取max(dp[i][k]-sum[i][k])
k应该满足time[i][k][j] <= k
随着j的变化k的范围是一个滑动窗口,用单调队列去维护。
右边走转移 dp[i][k] + sum[i][k] - sum[i][j],类似处理。
转移为O(1),复杂度为O(N*M)
#include<bits/stdc++.h> using namespace std; const int N = 102, M = 1e4+5; int n, m, k; int h[N][M], t[N][M]; int dp[N][M]; int q[M]; //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif while(scanf("%d%d%d", &n, &m, &k), n+m+k){ n++; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m ;j++){ scanf("%d",h[i]+j); h[i][j] += h[i][j-1]; } } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m ;j++){ scanf("%d",t[i]+j); t[i][j] += t[i][j-1]; } } for(int i = 1; i <= n; i++){ #define maintain(diff) while(hd<rl && diff(j,q[hd]) > k) hd++; #define inst(val) while(hd<rl && val(q[rl-1]) <= val(j)) rl--; q[rl++] = j; int hd = 0, rl = 0; #define dis(x) (t[i][x]) #define lval(x) (dp[i-1][x] - h[i][x]) #define ldis(j,k) dis(j)-dis(k) for(int j = 0; j <= m; j++){ inst(lval) maintain(ldis) dp[i][j] = lval(q[hd])+h[i][j]; } hd = rl = 0; #define rval(x) (dp[i-1][x] + h[i][x]) #define rdis(j,k) dis(k)-dis(j) for(int j = m; j >= 0; j--){ inst(rval) maintain(rdis) dp[i][j] = max(dp[i][j],rval(q[hd])-h[i][j]); } } int ans = 0; for(int j = 0; j <= m; j++){ ans = max(ans,dp[n][j]); } printf("%d ",ans); } return 0; }