ARC 067 F Yakiniku Restaurants - 单调栈 - 前缀和

题目大意:(我翻译的开森)
n个餐馆排成一条直线,相邻两个餐馆有个距离;m张餐票,每张最多能用一次,并且在不同的店使用收益不同。起点终点任意,问总收益减去总路程最大是多少。
n5000,m200 n ≤ 5000 , m ≤ 200
题解:区间确定的时候每张餐票会用在最划算的那个餐馆,反过来对每个餐票和每个餐厅考虑选择哪些区间会使得这张餐票用在这家餐馆。显然是左右遇到更大的之前都可以。为避免重复计数钦定对一个区间和一张餐票若有多解则选最左的就可以了,然后就是一个矩形加和最后问单点最值。暴力差分即可,事实上线段树可以nlgn。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<utility>
#define lint long long
#define gc getchar()
#define mp make_pair
#define fir first
#define sec second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define clr(a,n) memset(a,0,sizeof(int)*((n)+1))
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
#define N 5010
#define M 210
lint s[N],v[N][N];int b[M][N];int L[N],R[N],stc[N];
int main()
{
    int n=inn(),m=inn();rep(i,2,n) s[i]=s[i-1]+inn();
    rep(i,1,n) rep(j,1,m) b[j][i]=inn();
    rep(i,1,m)
    {
        int top=0;
        for(int j=1;j<=n;j++)
        {
            while(top&&b[i][j]>b[i][stc[top]]) R[stc[top--]]=j-1;
            stc[++top]=j;
        }
        rep(j,1,top) R[stc[j]]=n;
        top=0;
        for(int j=n;j>=1;j--)
        {
            while(top&&b[i][j]>=b[i][stc[top]]) L[stc[top--]]=j+1;
            stc[++top]=j;
        }
        rep(j,1,top) L[stc[j]]=1;
        rep(j,1,n) v[L[j]][j]+=b[i][j],
            v[L[j]][R[j]+1]-=b[i][j],
            v[j+1][j]-=b[i][j],
            v[j+1][R[j]+1]+=b[i][j];
//      debug(i)ln;rep(j,1,n) debug(j)sp,debug(b[i][j])sp,debug(L[j])sp,debug(R[j])ln;
    }
    lint ans=0ll;
    rep(i,1,n) rep(j,1,n)
    {
        v[i][j]=v[i][j]+v[i-1][j]+v[i][j-1]-v[i-1][j-1];
        if(i<=j) ans=max(ans,v[i][j]-(s[j]-s[i]));
    }
    return !printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值