【AtCoder】ARC067 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 单调栈+矩阵差分的更多相关文章
- 牛客多校第三场F Planting Trees 单调栈
Planting Trees 题意 给出一个矩阵,求最大矩阵面积满足该矩阵中任2元素的绝对值之差小于等于M T<1000) (n<500)但是题目明示单组(n*3)可过 分析 又是矩阵问题 ...
- AtCoder Regular Contest 067 F - Yakiniku Restaurants
题意: 有n个餐厅排成一排,第i个与第i+1个之间距离是Ai. 有m种食物,每种食物只能在一个餐厅里吃,第j种食物在第i个餐厅里吃的收益是$b[i][j]$. 选择每种食物在哪个餐厅里吃,使收益减去走 ...
- AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)
题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...
- 2019牛客暑假多校赛(第二场) F和H(单调栈)
F-Partition problem https://ac.nowcoder.com/acm/contest/882/F 题意:输入一个数n,代表总共有2n个人,然后每个人对所有人有个贡献值,然后问 ...
- Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并
F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...
- AtCoder Grand Contest 005【A栈模拟,B单调栈】
挖草,AtCoder实在是太吊了~ %%%,目前只A了两题: A题: 就是利用栈模拟一下就好了:S进栈,T的话有S就出栈,然后len减一下就好了: #include <bits/stdc++.h ...
- 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 ...
- 2019牛客暑期多校训练营(第二场)-H Second Large Rectangle(次大子矩阵,降维,直方图+单调栈)
题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目:给n×m的由01组成的矩阵,求次大全1子矩阵的大小. 思路:第一步还是降维操作,用a[i][j]记录 ...
- Atcoder Regular Contest 058 D - 文字列大好きいろはちゃん / Iroha Loves Strings(单调栈+Z 函数)
洛谷题面传送门 & Atcoder 题面传送门 神仙题. mol 一发现场(bushi)独立切掉此题的 ycx %%%%%%% 首先咱们可以想到一个非常 naive 的 DP,\(dp_{i, ...
随机推荐
- Alpha阶段敏捷冲刺⑥
1.提供当天站立式会议照片一张. 每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 实现对账单条目的编辑 初步设计设置页面 今天要完成的工作. 账单明细 ...
- Delphi中BCD和Currency类型
用了这些年的Delphi,竟然对Currency及TBCDField一知半解,下文给了很好的讲解,值得一读. 一. BCD类型 BCD即Binary-Coded Decimal?,在Del ...
- call()方法和apply()方法
最近又遇到了JacvaScript中的call()方法和apply()方法,而在某些时候这两个方法还确实是十分重要的,那么就让我总结这两个方法的使用和区别吧. 1. 每个函数都包含两个非继承而来的方法 ...
- PHP时间格式化参数表笔记
date_create_from_format() 函数返回一个根据指定格式进行格式化的新的 DateTime 对象.通常需要配合date_format()函数使用 语法: date_create_f ...
- python 安装pymssql
error: command 'gcc' failed with exit status 1 ---------------------------------------- Command &quo ...
- HTTP压力测试工具wrk的安装及测试
本次在VMware虚拟机的CentOS6.3系统中进行安装wrk压测工具,具体如下: 一.预先安装需求项 为了安装顺利,不受权限的限制,首先可以把用户切换为root用户# su + 输入root用户对 ...
- Mysql的两种引擎的区别
Innodb引擎概述 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别.该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MyS ...
- 微信小程序 功能函数 定时震动
ffn: function () { let nnn = this.data.nnn nnn += 1; this.setData({ nnn: nnn }); if (nnn > 10) { ...
- 从解决一个java.lang.NoSuchMethodError想到的
今天在发布系统部署一个web app的时候,发现应用服务器(tomcat 7.0.26)不能正常启动,于是远程登陆到服务器上查看应用服务器的启动日志,在tomcat_home的logs/localho ...
- check the manual that corresponds to your MySQL server version for the right syntax to use near 'type=InnoDB' at line 7
第一种是:解决MySQL的版本问题(我用的是mysql 5.5版本),mysql 5.0版本以后的数据库方言是:org.hibernate.dialect.MySQ5LInnoDBDialect.第二 ...