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;
}
posted @ 2021-10-13 18:47  lahlah  阅读(48)  评论(0编辑  收藏  举报