【题目】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. Linux网卡配置文件路径是什么?要使服务器上外网,必须满足的条件有哪些?需要配置什么?

    Linux网卡配置文件路径是什么?要使服务器上外网,必须满足的条件有哪些?需要配置什么?    答:    网卡配置文件路径:/etc/sysconfig/network-scripts/ifcfg- ...

  2. 用户数以及psp

    小组名称:好好学习 小组成员:林莉  王东涵   胡丽娜   宫丽君 项目名称: 记账本 alpha发布48小时以后用户数如何,是否达到预期目标,为什么,是否需要改进,如何改进(或理性估算). 首先我 ...

  3. Git命令提交项目代码

    Git客户端安装 今天就结合`GitHub`,通过`Git`命令,来了解如何实现开源代码库以及版本控制 GitHub是一个面向开源及私有软件项目的托管平台,因为只支持Git 作为唯一的版本库格式进行托 ...

  4. PHP 配置默认SSL CA证书

    1.从CURL 官网下载CA 证书(当然也可以选择自己创建SSL CA证书,详情参考 https://blog.csdn.net/scuyxi/article/details/54898870 ,或自 ...

  5. myeclipse8.6 注册码

    MyEclipse8.6 注册码 别处找的均是8.6版本,可以使用到2014年一:MyEclipse Standard Edition: zhucemLR7ZL-655954-695876566190 ...

  6. BZOJ1226 SDOI2009学校食堂(状压dp)

    由于Bi<=7,考虑状压. 如果考虑前i个位置的话,状态里需要压入前7个人后7个人,显然是跑不动的. 那么改成考虑前i个人.于是设f[i][j][k]表示前i个人都已吃完饭,i+1后面7个人的吃 ...

  7. P1198 [JSOI2008]最大数

    题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度.(L>0) ...

  8. Java参数引用传递之例外:null

    今天写链表的时候写了一个函数,实参是一个空链表,应该是按引用传参,但是在函数内修改了链表,外部的链表没有变化. 原来是null作为参数传递的时候,就不是引用传参了. 引自:http://blog.cs ...

  9. nmon

    http://www.cnblogs.com/me-sa/articles/centos0006.html

  10. Android 资源目录 相关知识 raw、 drawable、 values..

    一定要看的 Android 资源目录的相关知识 raw drwable valueshttp://blog.csdn.net/shichexixi/article/details/5985677 ht ...