【arc067F】Yakiniku Restaurants

Portal --> arc067F

Solution

  这题其实好像。。思维难度不算特别大==(众神犇:这不是弱智题吗?)但是我再一次在场上想到之后自己fou掉了正确的解法qwq真是全场最佳qwq

  首先比较容易想到走的时候为了让减去的值尽量小,肯定是从前往后走的

  然而这样想好像没有什么用== 这个时候又有一个很粗暴的想法:如果说我们已经钦定了走的是哪一段(假设是从\(l\)走到\(r\)),那么我们只要求出每张票在这段区间中的价值的最大值,然后加起来再减掉钦定的距离就是答案了

  枚举\(l\)\(r\)\(n^2\)的,现在我们需要一个比较快速的求区间最大值之和的方法

  最大值的话。。我们考虑固定左端点\(l\),然后移动\(r\),容易发现在这个过程中对于每一张票,它的最大值是单调的(不下降),我们考虑对于每一张票用一个单调栈来维护一下当前最大值

  但是这样还不能够统计快速统计到当前区间的最大值之和

  我们考虑维护一个数组\(val\)\(val[i]\)表示当左端点\(l\)固定的时候,右端点\(r\)\(i\)时的最大值增量,这个东西可以在单调栈维护最大值的时候一并处理,具体一点的操作就是:对于每一个新加进栈里的元素(也就是当前的最大值),我们记这个元素的位置为\(pos\),在\(val[pos]\)处加上该元素的值,并在栈中前一个元素的位置减去当前元素的值(移到那里去的话就不包含当前元素了),然后在元素出栈的时候,对于当前出栈的元素,在它的位置上减去这个元素的值,再在它的栈中前一个元素的位置加上它的值(其实就是和上面的操作反过来,相当于消除这个元素的影响)

  然后查询的时候,我们从大到小枚举\(l\)(单调栈需求),然后将当前行的每张票的值丢到其对应的单调栈里面,从小到大枚举\(r\),不断加上\(val\)这个增值,更新答案,在往后走的时候减去距离的代价即可

  时间复杂度是\(O(n(n+m))\)的,然而好像有人写的是\(O(nmlogn)\)(还是\(logm\)忘记了qwq)也可以过qwq

  最后吐槽一下自己的弱智操作:想到了这个做法之后非常开心,但是马上又觉得我要先把所有左端点对应的增值数组先算出来,然后最后统计的时候再累加然后就爆炸了==
  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=5010,TOP=10;
int a[N][N];
ll val[N];
int dis[N];
int n,m;
ll ans;
struct Stack{
	int st[N],which,top;
	void init(int _which){which=_which;}
	void push(int x){
		while (top&&a[st[top]][which]<=a[x][which]){
			val[st[top]]-=a[st[top]][which];
			if (top>1)
				val[st[top-1]]+=a[st[top]][which];
			--top;
		}
		st[++top]=x;
		val[st[top]]+=a[st[top]][which];
		if (top>1)
			val[st[top-1]]-=a[st[top]][which];
	}
}St[N];

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	ll now;
	scanf("%d%d",&n,&m);
	for (int i=1;i<n;++i) scanf("%d",dis+i);
	memset(val,0,sizeof(val));
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			scanf("%d",&a[i][j]);
	for (int i=1;i<=m;++i) St[i].init(i);
	for (int l=n;l>=1;--l){
		for (int i=1;i<=m;++i) 
			St[i].push(l);
		now=0;
		for (int r=l;r<=n;++r){
			now+=val[r];
			ans=max(ans,now);
			now-=dis[r];
		}
	}
	printf("%lld\n",ans);
}
posted @ 2018-09-11 19:33  yoyoball  阅读(300)  评论(0编辑  收藏  举报