SPOJ SP10622 DIFERENC - DIFERENCIJA 题解

Description

\(\sum\limits_{i=1}^{n}\sum\limits_{j=i}^{n}(\max\limits_{k=i}^{j}a_k-\min\limits_{k=i}^{j}a_k)\)

其中 \(n\le3\times 10^{5}\)

Solution

解法一

\(O(n^2)\) 的朴素算法是很容易想到的:首先外层循环枚举每个左端点,内层循环枚举右端点的同时维护区间内的最大值和最小值即可。

这样的朴素算法很难继续优化,主要是因为枚举的是区间。区间个数太多并且很难一起处理。于是可以考虑枚举每一个数的贡献。

显然有

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

\[=\sum\limits_{i=1}^{n}\sum\limits_{j=i}^{n}\max\limits_{k=i}^{j}a_k-\sum\limits_{i=1}^{n}\sum\limits_{j=i}^{n}\min\limits_{k=i}^{j}a_k \]

因此原问题可以分成最大值之和与最小值之和两个几乎等价的子问题,这里只讨论最大值的部分。对于每个数 \(a_i\),能产生贡献的区间只有 \([l_i+1,r_i-1]\),其中 \(l_i\) 表示 \(a_i\) 左边第一个大于 \(a_i\) 的数的下标,\(r_i\) 表示 \(a_i\) 右边第一个大于 \(a_i\) 的数的下标。在这个区间内所有包含 \(a_i\) 的子区间的区间最大值都是 \(a_i\)。这样的子区间共有 \((i-l_i)\times(r_i-i+1)\) 个,因此 \(a_i\) 能产生的贡献就是 \(a_i\times(i-l_i)\times(r_i-i+1)\)。使用单调栈即可在 \(O(n)\) 的时间内求出 \(l_i\)\(r_i\)

最小值的部分同理。

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

解法二

考虑动态规划。这里我们仍然是只讨论最大值的部分。设 \(f_i\) 表示所有以 \(a_i\) 结尾的子序列中的最大值的和。状态转移方程:

\[f_i=f_{l_i}+(i-l_i)\times a_i \]

其中 \(l_i\) 表示 \(a_i\) 左边第一个大于 \(a_i\) 的数的下标。如果不存在这样的数,\(l_i\) 就等于 \(0\)。根据 \(l_i\) 的定义,显然有 \(a_i=\max\limits_{j=l_i+1}^{i}a_j\),也就是说,所有左端点位于 \([l_i+1,i]\),右端点为 \(i\) 的子序列中的最大值都是 \(a_i\)\(a_i\) 的贡献就是 \((i-l_i)\times a_i\)。由于 \(a_i<a_{l_i}\)\(a_i\) 不会对左端点位于 \([1,l_i]\) 的子序列产生任何影响,那一部分的贡献就是 \(f_{l_i}\)

在枚举 \(i\) 的同时用单调栈维护一下 \(l_i\) 即可。最小值的部分同理。

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

这里给出了解法二的代码实现。

Code

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=3e5+10;
const int INF=0x3f3f3f3f;
int a[N];
int sta[N],top;
LL f[N];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	top=0,a[0]=INF;
	LL ans=0;
	for(int i=1;i<=n;i++)
	{
		while(a[i]>=a[sta[top]]) top--;
		LL x=sta[top];
		f[i]=f[x]+(i-x)*a[i],ans+=f[i];
		sta[++top]=i;
	}
	top=0,a[0]=0;
	memset(f,0,sizeof(f));
	for(int i=1;i<=n;i++)
	{
		while(a[i]<=a[sta[top]]) top--;
		LL x=sta[top];
		f[i]=f[x]+(i-x)*a[i],ans-=f[i];
		sta[++top]=i;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   __Star_Sky  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示