P6406 [COCI2014-2015] Norma 分治+数学

题意:

戳这里

分析:

  • 暴力

\(O(n \log n)\) 预处理 ST表 然后 \(O(n^2)\) 枚举左右端点

  • 正解

我们要优化统计答案的复杂度,也就是说我们需要大概 \(O(n \log n)\) 的复杂度 来统计答案

很容易想到每一个点作为最大值和最小值的影响是一段区间,那么我们就递归通过分治来统计区间的贡献,和 CDQ 分治的思想差不多,我们只需要统计跨过区间中点的影响,剩下的递归下去

具体来说,每一次分治中,我们枚举左端点 \(i\) ,统计以 \(i\) 为左端点的序列的答案,分三种情况讨论 , 默认 \(p\le q\)

变量声明:

mx = $ max(a_i\dots a_{mid})$ ; mn = $ min(a_i\dots a_{mid})$

mna = \(\sum mn\) ; mnb = \(\sum mn\times i\)

mxa = \(\sum mx\) ; mxb = $\sum mx\times i $

mma = \(\sum mx \times mn\) ; mmb = \(\sum mx\times mn \times i\)

p 表示满足 \(mn \leqslant min \{ a[mid\!+\!1] \cdots a[j] \}\) 的最大的 p 的位置
q 表示满足 \(mx \geqslant max \{ a[mid\!+\!1] \cdots a[k] \}\) 的最大的 q 的位置。

  1. \(mx,mn\) 都取 \([mid+1,p]\)

\(ans \Leftrightarrow \sum mn\times mx \times (j-i+1)\)

  1. \(mx\)\(mn\) 不取 \([p,q]\)

\(ans \Leftrightarrow mx\times \sum min_j\times (j-i+1)\)

  1. \(mx,mn\) 都不取 \([q,r]\)

\(ans\Leftrightarrow \sum max_j\times min_j \times (j-i+1)\)

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxn = 5e5+5;
	const long long mod = 1e9;
	long long a[maxn],mxa[maxn],mxb[maxn],mna[maxn],mnb[maxn],mma[maxn],mmb[maxn];
	long long ans,n,mn,mx;
	
	void qm(long long x){return (void)(ans=(ans+x>=mod?ans+x-mod:ans+x));}
	long long S(long long l,long long r){return (long long)(l+r)*(r-l+1)/2%mod;}
	
	void solve(int l,int r)
	{
		if(l==r){return (void)(qm(a[l]*a[l]%mod));}
		long long mid=(l+r)>>1;
		solve(l,mid);solve(mid+1,r);
		mn=mod;mx=0;
		mxa[mid]=mxb[mid]=mna[mid]=mnb[mid]=mma[mid]=mmb[mid]=0;
		for(int j=mid+1;j<=r;j++)
		{
			mn=min(mn,a[j]);mx=max(mx,a[j]);
			mxa[j]=(mxa[j-1]+mx)%mod;
			mxb[j]=(mxb[j-1]+mx*j%mod)%mod;
			mna[j]=(mna[j-1]+mn)%mod;
			mnb[j]=(mnb[j-1]+mn*j%mod)%mod;
			mma[j]=(mma[j-1]+mn*mx%mod)%mod;
			mmb[j]=(mmb[j-1]+mn*mx%mod*j%mod)%mod;
		}
		mn=mod;mx=0;
		for(int q=mid+1,p=mid+1,i=mid;i>=l;i--)
		{
			mn=min(mn,a[i]);mx=max(mx,a[i]);
			while(p<=r&&mn<a[p]) p++;
			while(q<=r&&mx>a[q]) q++;
			if(p<q)
			{
				qm(mn*mx%mod*S(mid-i+2,p-i)%mod);
				qm((mnb[q-1]-mnb[p-1]+mod)*mx%mod+(1-i+mod)*mx%mod*(mna[q-1]-mna[p-1]+mod)%mod);
				qm((mmb[r]-mmb[q-1]+mod)%mod+(1-i+mod)%mod*(mma[r]-mma[q-1])%mod);
			}
			else
			{
				qm(mn*mx%mod*S(mid-i+2,q-i)%mod);
				qm((mxb[p-1]-mxb[q-1]+mod)*mn%mod+(1-i+mod)*mn%mod*(mxa[p-1]-mxa[q-1]+mod)%mod);
				qm((mmb[r]-mmb[p-1]+mod)%mod+(1-i+mod)%mod*(mma[r]-mma[p-1]+mod)%mod);
			} 
		}
	}
	
	void work()
	{
		n=read();
		for(int i=1;i<=n;i++) a[i]=read();
		solve(1,n);
		printf("%lld\n",ans%mod);
	}

}

int main()
{
	zzc::work();
	return 0;
}

posted @ 2020-11-27 20:48  youth518  阅读(109)  评论(0编辑  收藏  举报