【题目链接】
【算法】
不难看出,这题可以用动态规划来解决
f[i][j]表示第i行第j列能够取得的最大分数
则如果向右走,状态转移方程为f[i][j]=max{f[i-1][k]+a[i][k]+a[i][k+1]+...+a[i][j]}(i-T<=k<=j)
如果向左走,则状态转移方程为f[i][j]=max{f[i-1][k]+a[i][k]+a[i][k-1]+...+a[i][j]} (j<=k<=i+T)
用前缀和优化,s[i][j]表示第i行前j个数的和
则式子被简化为 :
向右走 : f[i][j] = max{f[i-1][k]+s[i][j]-s[i][k-1]} (i-T<=k<=j)
向左走 : f[i][j] = max{f[i-1][k]+s[i][k]-s[i][j-1]} (j<=k<=i+T)
但是这样做还是会TLE,所以我们继续优化 :
我们可以将第一个状态转移方程中s[i][j]提出,式子被写成f[i][j] = max{f[i-1][k]-s[i][k-1]}+s[i][j] (i-T<=k<=j)
将第二个状态转移方程中s[i][j-1]提出,式子被写成f[i][j] = max{f[i-1][k]+s[i][k]}+s[i][j-1] (j<=k<=i+T)
于是我们就可以用单调队列维护最值,时间复杂度 : O(数据组数*N*M)
【代码】
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100
#define MAXM 10000
typedef long long LL;
struct info {
LL x,val;
};
LL i,j,N,M,X,T,tmp,ans;
LL a[MAXN+10][MAXM+10],s[MAXN+10][MAXM+10],f[MAXN+10][MAXM+10];
deque<info> q;
template <typename T> inline void read(T &x) {
LL f = 1; x = 0;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> inline void write(T x) {
if (x < 0) { putchar('-'); x = -x; }
if (x > 9) write(x/10);
putchar(x%10+'0');
}
template <typename T> inline void writeln(T x) {
write(x);
puts("");
}
int main() {
while (cin >> N >> M >> X >> T) {
ans = -2e9;
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
read(a[i][j]);
}
}
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
s[i][j] = s[i][j-1] + a[i][j];
}
}
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
f[i][j] = -2e9;
}
}
for (i = X; i >= X - T; i--) f[1][i] = s[1][X] - s[1][i-1];
for (i = X; i <= X + T; i++) f[1][i] = s[1][i] - s[1][X-1];
for (i = 2; i <= N; i++) {
q.clear();
for (j = 1; j <= M; j++) {
while ((!q.empty()) && (j - q.front().x > T)) q.pop_front();
tmp = f[i-1][j] - s[i][j-1];
while ((!q.empty()) && (tmp >= q.back().val)) q.pop_back();
q.push_back((info){j,tmp});
f[i][j] = q.front().val + s[i][j];
}
q.clear();
for (j = M; j >= 1; j--) {
while ((!q.empty()) && (q.front().x - j > T)) q.pop_front();
tmp = f[i-1][j] + s[i][j];
while ((!q.empty()) && (tmp >= q.back().val)) q.pop_back();
q.push_back((info){j,tmp});
f[i][j] = max(f[i][j],q.front().val-s[i][j-1]);
}
}
for (i = 1; i <= M; i++) ans = max(ans,f[N][i]);
writeln(ans);
}
return 0;
}