【题目】F - Yakiniku Restaurants

【题意】给定n和m,有n个饭店和m张票,给出Ai表示从饭店i到i+1的距离,给出矩阵B(i,j)表示在第i家饭店使用票j的收益,求任选起点和终点的最大(收益-代价)。n<=5000,m<=200。

【算法】单调栈+矩阵差分

【题解】直接枚举区间,很难同时计算m张票,我们反过来考虑每个B(i,j)的贡献。

对于B(i,j),令x为满足x<i,B(x,j)>B(i,j)的最大的x,令y为满足y>i,B(y,j)>B(i,j)的最小的y,则B(i,j)会对所有l∈[x+1,i]&&r∈[i,y-1]的区间贡献。

其中,x和y可以维护单调栈求得。(因为求最大,所以越早越没用)

现在将区间[x,y]视为平面上的点(x,y),那么就是矩阵加B(i,j),最后扫描每个点,这个用差分就可以了。

复杂度O(n^2+nm)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
int n,m,b[maxn][maxn],s[maxn],l[maxn][maxn],r[maxn][maxn],w[maxn];
ll a[maxn],A[maxn][maxn];
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-];
for(int i=;i<=n;i++)for(int j=;j<=m;j++)scanf("%d",&b[j][i]);
for(int i=;i<=m;i++){
int top=;
for(int j=;j<=n;j++){
while(top&&b[i][j]>s[top])top--;
if(top)l[i][j]=w[top]+;else l[i][j]=;
s[++top]=b[i][j];w[top]=j;
}
top=;
for(int j=n;j>=;j--){
while(top&&b[i][j]>s[top])top--;
if(top)r[i][j]=w[top]-;else r[i][j]=n;
s[++top]=b[i][j];w[top]=j;
}
for(int j=;j<=n;j++){
A[l[i][j]][j]+=b[i][j];
A[l[i][j]][r[i][j]+]-=b[i][j];
A[j+][j]-=b[i][j];
A[j+][r[i][j]+]+=b[i][j];
}
}
ll ans=-1ll<<;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++)A[i][j]+=A[i][j-];
for(int j=;j<=n;j++)A[i][j]+=A[i-][j];
for(int j=i;j<=n;j++)ans=max(ans,A[i][j]-a[j]+a[i]);
}
printf("%lld",ans);
return ;
}

【另一解】

枚举左端点L。单看一张饭票,用单调栈预处理f[i]表示最小的x满足x>i&&B(x)>B(i),那么这张饭票的贡献其实是一个从L开始长度为k的递增位置序列c[],其中c[i]的贡献是B(c[i])-B(c[i-1])。对于所有饭票都将c[i]的贡献叠加到数组g[]上,那么处理完后g[i]表示区间包含i得到的贡献。此时就可以枚举右端点更新答案。

然后考虑左端点移动删除L,即更新为从L+1开始递增的数字。原来c[1]=L,那么实际上到c[2]就停止了,c[2]需要额外减掉B(c[2])-B(c[1])来消除上次的贡献。这个过程暴力更新,复杂度是正确的,因为只会被最近的比它大的数字引发更新,复杂度O(n^2+nm)。

这种思想是考虑左端点的移动对答案的影响,而非右端点。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
int read(){
int s=,t=;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
int n,m,a[][maxn],f[][maxn],s[maxn],w[maxn];
ll A[maxn],g[maxn];
int main(){
n=read();m=read();
for(int i=;i<=n;i++)A[i]=read();
for(int i=;i<=n;i++)for(int j=;j<=m;j++)a[j][i]=read();
int top=;
for(int i=;i<=m;i++){
top=;
for(int j=n;j>=;j--){
while(top&&a[i][j]>=s[top])top--;
if(top)f[i][j]=w[top];else f[i][j]=n+;
s[++top]=a[i][j];w[top]=j;
}
}
for(int i=;i<=m;i++){
int j=;g[]+=a[i][];
while(f[i][j]<=n)g[f[i][j]]+=a[i][f[i][j]]-a[i][j],j=f[i][j];
}
ll ans=-1ll<<,sum=g[];ans=max(ans,sum);
for(int i=;i<=n;i++)ans=max(ans,sum=sum-A[i]+g[i]);
for(int k=;k<=n;k++){
for(int i=;i<=m;i++){
int j=k,pre=;
while(j<=n&&j!=f[i][k-])g[j]+=a[i][j]-a[i][pre],pre=j,j=f[i][j];
g[j]-=a[i][j]-a[i][k-];g[j]+=a[i][j]-a[i][pre];
}
sum=g[k];ans=max(ans,sum);
for(int j=k+;j<=n;j++)ans=max(ans,sum=sum-A[j]+g[j]);
}
printf("%lld",ans);
return ;
}

【AtCoder】ARC067 F - Yakiniku Restaurants 单调栈+矩阵差分的更多相关文章

  1. 牛客多校第三场F Planting Trees 单调栈

    Planting Trees 题意 给出一个矩阵,求最大矩阵面积满足该矩阵中任2元素的绝对值之差小于等于M T<1000) (n<500)但是题目明示单组(n*3)可过 分析 又是矩阵问题 ...

  2. AtCoder Regular Contest 067 F - Yakiniku Restaurants

    题意: 有n个餐厅排成一排,第i个与第i+1个之间距离是Ai. 有m种食物,每种食物只能在一个餐厅里吃,第j种食物在第i个餐厅里吃的收益是$b[i][j]$. 选择每种食物在哪个餐厅里吃,使收益减去走 ...

  3. AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)

    题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...

  4. 2019牛客暑假多校赛(第二场) F和H(单调栈)

    F-Partition problem https://ac.nowcoder.com/acm/contest/882/F 题意:输入一个数n,代表总共有2n个人,然后每个人对所有人有个贡献值,然后问 ...

  5. Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并

    F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...

  6. AtCoder Grand Contest 005【A栈模拟,B单调栈】

    挖草,AtCoder实在是太吊了~ %%%,目前只A了两题: A题: 就是利用栈模拟一下就好了:S进栈,T的话有S就出栈,然后len减一下就好了: #include <bits/stdc++.h ...

  7. Manthan, Codefest 18 (rated, Div. 1 + Div. 2) F 单调栈 + 贡献 + 计数

    https://codeforces.com/contest/1037/problem/F 题意 function z(array a, integer k): if length(a) < k ...

  8. 2019牛客暑期多校训练营(第二场)-H Second Large Rectangle(次大子矩阵,降维,直方图+单调栈)

    题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目:给n×m的由01组成的矩阵,求次大全1子矩阵的大小. 思路:第一步还是降维操作,用a[i][j]记录 ...

  9. Atcoder Regular Contest 058 D - 文字列大好きいろはちゃん / Iroha Loves Strings(单调栈+Z 函数)

    洛谷题面传送门 & Atcoder 题面传送门 神仙题. mol 一发现场(bushi)独立切掉此题的 ycx %%%%%%% 首先咱们可以想到一个非常 naive 的 DP,\(dp_{i, ...

随机推荐

  1. apache +PHP多版本 切换的问题

    在开发中切换php版本的时候出错 经过2小时的日子排查终于找到是因为切换版本后加载的php7ts.dll模块还是原来版本的,因此保pid file 错误 解决方法 PHPIniDir "H: ...

  2. ySQL性能优化的21个最佳实践 和 mysql使用索引

    MySQL性能优化的21个最佳实践 和 mysql使用索引 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我 ...

  3. android获取view宽高的几种方法

    在onCreate方法中我们通过mView.getWidth()和mView.getHeight()获取到的view的宽高都是0,那么下面几种方法就可以在onCreate方法中获取到view的宽高. ...

  4. Linux下如何确认磁盘是否为SSD

    方法 法1:通过查看/sys/block/sda/queue/rotational 通过cat /sys/block/sda/queue/rotational进行查看,返回值0即为SSD:返回1即为H ...

  5. HDFS问题集(一),使用命令报错:com.google.protobuf.ServiceException:java.lang.OutOfMemoryError:java heap space

    仅个人实践所得,若有不正确的地方,欢迎交流! 一.起因 执行以下两条基本的HDFS命令时报错 hdfs dfs -get /home/mr/data/* ./ hdfs dfs -ls /home/m ...

  6. go语言切片作为函数参数的研究

    slice作为函数参数是值传递 golang中的切片slice底层通过数组实现,slice类似一个结构体,其中一个字段保存的是底层数组的地址,还有长度(len) 和 容量(cap)两个字段. 结构体作 ...

  7. codeforces div1 & div2 参与人员分数统计

    Analysis helps to see the nature of things.

  8. rovio视觉里程计的笔记

    rovio是一个紧耦合,基于图像块的滤波实现的VIO. 他的优点是:计算量小(EKF,稀疏的图像块),但是对应不同的设备需要调参数,参数对精度很重要.没有闭环,没有mapping thread.经常存 ...

  9. 图像bayer格式介绍以及bayer插值原理CFA

    1 图像bayer格式介绍 bayer格式图片是伊士曼·柯达公司科学家Bryce Bayer发明的,Bryce Bayer所发明的拜耳阵列被广泛运用数字图像. 对于彩色图像,需要采集多种最基本的颜色, ...

  10. [python]python安装包错误

    “UnicodeDecodeError: ‘ascii’ codec can’t decode : ordinal not )” 在windows XP上 解决方法: Solution: ====== ...