首页 > 其他分享 >题解 DIFERENC - DIFERENCIJA

题解 DIFERENC - DIFERENCIJA

时间:2023-10-10 22:24:28浏览次数:40  
标签:DIFERENC DIFERENCIJA le sta int 题解 top 计算 复杂度

题目描述

给出一个长度为 \(n\) 的序列 \(a_i\),求出下列式子的值:

\[\sum_{i=1}^n \sum_{j=i}^n (\max \limits_{i \le k \le j} a_k-\min \limits_{i \le k \le j}a_k) \]

即定义一个子序列的权值为序列内最大值与最小值的差。求出所有连续子序列的权值和。

具体思路

暴力思路很好想,就是按照式子来打,然后区间最大值和区间最小值可以用数组预处理一下。

时间复杂度:\(O(n^2)\)。

那么我们发现,如果我们的两个求和不拆掉那么时间复杂度就不正确,那么思路就很显然:计算每个 \(a_i\) 算了多少遍。

可以考虑将 \(a_i\) 看成一个宽度为 \(1\),高度为 \(a_i\) 的矩形。

image

如图所示,我们来考虑上图中红色部分作为最大值被计算了多少次。

  • 当 \(i=2\),当 \(j=3,4\) 时 \(a_3\) 被计算了一次。

  • 当 \(i=3\),当 \(j=3,4\) 时 \(a_3\) 被计算了一次。

那我们发现,\(i\) 这一层循环 \(a_k\) 被计算的次数是 \(k\) 到上一个比它大的位置,而 \(j\) 这一层循环 \(a_k\) 被计算的次数时 \(k\) 到下一个比它大的位置。

设 \(i\) 这层循环计算的次数是 \(l_k\),\(j\) 这层循环计算的次数是 \(r_k\)。

\[ans=\sum_{k=1}^n l_k \times r_k \times a_k \]

如果我们暴力枚举每一个点,然后暴力找上一个比它大的位置以及下一个比它大的位置,时间复杂度:\(O(n^2)\)。

这不没优化吗?

上面这个图,显然就很有单调栈的味道。

从左往右依次枚举每一个点,维护一个单调下降的栈,如果当前的点比栈顶要大,那么更新栈顶的信息,同时将栈顶踢出栈。

然后我们就愉快的解决了这个问题。

维护最小值也是同样的道理。

时间复杂度:\(O(n)\)。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
const int inf=0x3f3f3f3f;
int top,sta[N],l[N],r[N],a[N];
signed main(){
	int n;scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	top=1;sta[top]=1;
	l[1]=1;
	for(int i=2;i<=n;i++){
		while(top&&a[i]>a[sta[top]]){
			r[sta[top]]=i-sta[top];
			top--;
		}
		l[i]=i-sta[top];
		sta[++top]=i;
	}
	a[n+1]=inf;
	while(top&&a[n+1]>a[sta[top]]){
		r[sta[top]]=n+1-sta[top];
		top--;
	}
	int maxn=0;
	for(int i=1;i<=n;i++){
		maxn=maxn+l[i]*r[i]*a[i];
	}
	top=1;sta[top]=1;
	l[1]=1;
	for(int i=2;i<=n;i++){
		while(top&&a[i]<a[sta[top]]){
			r[sta[top]]=i-sta[top];
			top--;
		}
		l[i]=i-sta[top];
		sta[++top]=i;
	}
	a[n+1]=0;
	while(top&&a[n+1]<a[sta[top]]){
		r[sta[top]]=n+1-sta[top];
		top--;
	}
	int minn=0;
	for(int i=1;i<=n;i++){
		minn=minn+l[i]*r[i]*a[i];
	}
	printf("%lld",maxn-minn);
	return 0;
}

标签:DIFERENC,DIFERENCIJA,le,sta,int,题解,top,计算,复杂度
From: https://www.cnblogs.com/reclusive2007/p/17755886.html

相关文章

  • p4801题解
    解题思路:确实是一道很好的贪心,但由于加上了水这个影响因素,使题目复杂度上升了不少。(考虑的东西多了嘛)输个入。对饼干温度无脑排序。求最小值。求最大值(用双指针做,后面会讲)。解题过程:先输入(这个步骤就不用我讲了)inta[1000005];longlongn,ws;longlongmin......
  • 洛谷P4158 [SCOI2009] 粉刷匠 题解
    所有的\(DP\),只要式子一推出来(不管复杂度),那就很简单了,因为优化是成千上万种的……思路1:我们考虑设\(f[i][j][k]\)表示:当前\(DP\)到第\(i\)块木板的第\(j\)个位置,共涂了\(k\)次,所能获得的最大收益。因为还要枚举当前这次涂是从哪到哪的,因此复杂度为\(O(NM^2T)\),实......
  • 洛谷P3300 [SDOI2013] 城市规划 题解
    [SDOI2013]城市规划题意:给你一个\(6\timesn\)的网格题,单点修改,询问区间联通块数,\(n\le10^5\)。解:看起来就很显然的一道题......线段树每个点用一个ufs维护连通性;我为了方便思考把图转成横着的了。写起来真是毒瘤......重点在于:\(\bullet\)1、建立叶节点。\(\bull......
  • 【ABC320C】题解
    AtCoderBeginnerContest320ProblemC-SlotStrategy2(Easy)题解题目简述给定\(3\)个长度为\(m\)的转盘,转动过后三个转盘分别可以在不同的时间停下,求停下时所有转盘都显示相同数字的最小时间。思路由于这题\(m\le100\),数据较水,所以可以先把每个数列都复制\(......
  • 【ABC320D】题解
    AtCoderBeginnerContest320ProblemD-RelativePosition题解题目保证不矛盾,就可以直接vector建图,然后dfs一遍,边权为\((w_x,w_y)\)表示坐标的差,从\(u=1\)开始搜索,设点\(u,v\)有一条无向边,\(v_x=u_x+w_x,v_y=u_y+w_y\),最后如果没有被标记过的话(也就是没有......
  • 【题解】Fibonacci-ish II
    传送门题目分析根据题目范围\(n\le30000\)并且此题可以离线维护这个很恶心的东西,所以我们考虑莫队。由于要求访问到任意一个区间都要求知道它有序之后的序列,所以这个东西可以用权值线段树维护。因此,此题正解是莫队+权值线段树。我们分类讨论一下加上一个数,删除一个数对答案......
  • 题解 P3894【[GDOI2014] 传送】
    难倒不难,128MB的空间限制快恶心死我了。我们设\(d_{u_0,u_1}\)表示到节点\((u_0,u_1)\)距离最近的叶子的距离,这个可以很容易换根DP求出。设\(p_{u_0}\)表示树\(u_0\)中距离最近的两个叶子的距离。设\(dis(u_0,u_1,v_0,v_1)\)(\(u_0=v_0\))表示树中两个节点\(u_1\)和......
  • 【ABC322C】题解
    AtCoderBeginnerContest322ProblemC-Festival题解Meaning-题意简述给定\(N\)和\(M\),还有\(M\)个正整数\(a_1\sima_n\),对于每个\(i\len\),求出\(a\)中第一个大于等于\(i\)的整数和\(i\)的差。Solution-题解思路题目保证\(a\)数组单增,所以就可......
  • 【LG-P7617】题解
    题解思路不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为\((4)_{10}\),那么他的状态压缩形式为\((00001)_2\)。当两个数在状态压缩表示下有一位相同,我们就认为这两个数是一对,每个......
  • 【ABC322D】题解
    AtCoderBeginnerContest322ProblemD-Polyomino题解Meaning-题意简述给定三个字符矩阵,求它们能不能拼在一起变成一个\(4\times4\)的全部是#的矩阵。Solution-题解思路大模拟。说简单也不简单,很复杂;但是说难呢,又不难。思路:搜索每一个矩阵的状态。0x001旋......