[arc067F]Yakiniku Restaurants[矩阵差分]

Description

传送门

Solution

假如我们确定了烧烤店区间[l,r],则票j必定会选择在B[i][j](l<=i<=r)最大的烧烤店使用。

反过来想,我们想要票j在第i个烧烤店使用,寻找可行区间[L,R]。

为了避免重复计算,我们钦定$k\epsilon [L,i]$时B[k][j]<B[i][j],$k\epsilon [i,R]$时B[k][j]<=B[i][j]。

接下来我们构造一个矩阵,矩阵的横坐标代表可行区间的左端点L,纵坐标表示可行区间的右端点R,对矩阵进行差分。使得当查询到子矩阵(L[i],i)-(i,R[i])时答案会加上B[i][j]。

Code

 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m,A[5010],B[5010][210];
ll matrix[5010][5010];int l[5010],r[5010];
int st[5010],tp;
ll sum[5010];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=2;i<=n;i++) {scanf("%d",&A[i]);sum[i]=sum[i-1]+A[i];}
    for (int i=1;i<=n;i++) 
        for (int j=1;j<=m;j++)
            scanf("%d",&B[i][j]);
    for (int j=1;j<=m;j++)
    {
        tp=0;
        for (int i=1;i<=n;i++)
        {
            while (tp&&B[i][j]>B[st[tp]][j]) r[st[tp--]]=i-1;
            st[++tp]=i;
        }
        while (tp) r[st[tp--]]=n;
        tp=0;
        for (int i=n;i;i--)
        {
            while(tp&&B[i][j]>=B[st[tp]][j]) l[st[tp--]]=i+1;
            st[++tp]=i;
        }
        while (tp) l[st[tp--]]=1;
        for (int i=1;i<=n;i++)
        {
            matrix[i+1][r[i]+1]+=B[i][j];
            matrix[l[i]][i]+=B[i][j];
            matrix[l[i]][r[i]+1]-=B[i][j];
            matrix[i+1][i]-=B[i][j];
        }
    }
    ll ans=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            matrix[i][j]+=matrix[i-1][j]+matrix[i][j-1]-matrix[i-1][j-1];
            if (i<=j) ans=max(ans,matrix[i][j]-(sum[j]-sum[i]));
        }
    cout<<ans;
}

 

转载于:https://www.cnblogs.com/coco-night/p/9630115.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值