AT2289 [ARC067D] Yakiniku Restaurants
https://www.luogu.com.cn/problem/AT2289
最后的路径肯定是一段单向的路,假设从右往左走
先假设只有一张餐票,那么对于一个右端点,可以维护所有左端点到这个右端点到最大值,可以用单调栈+数据结构维护
同样的,不考虑时间复杂度的话也可以用差分维护
那么对于 m m m张餐票,只需要用 m m m个单调栈维护,可以把贡献全部差分到一个数组上
时间复杂度就是
O
(
n
(
n
+
m
)
)
O(n(n+m))
O(n(n+m))
code:
#include<bits/stdc++.h>
#define N 5005
#define ll long long
using namespace std;
int n, m, a[N][N], sta[N][N], top[N];
ll s[N], b[N];
void add(int x, int y) {
b[x] += y;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 2; i <= n; i ++) scanf("%lld", &s[i]), s[i] += s[i - 1];
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]);
ll ans = 0;
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
while(top[j] && a[i][j] >= a[sta[j][top[j]]][j]) {
add(sta[j][top[j] - 1] + 1, -a[sta[j][top[j]]][j]);
add(sta[j][top[j]] + 1, a[sta[j][top[j]]][j]);
top[j] --;
}
sta[j][++ top[j]] = i;
add(sta[j][top[j] - 1] + 1, a[sta[j][top[j]]][j]);
add(sta[j][top[j]] + 1, -a[sta[j][top[j]]][j]);
}
ll ss = 0;
for(int l = 1; l <= i; l ++) {
ss += b[l];
ans = max(ans, ss - (s[i] - s[l]));
}
}
printf("%lld", ans);
return 0;
}