Jzoj5231 序列问题

给你序列A,定义f(l,r)=max{al,al+1,....,ar} , g(l,r)=min{al,al+1,....,ar}

求ΣΣf(i,j)*g(i,j) { i∈[1,n],j∈[i,n] }

哇第一道cdq分治的题诶,当时好像还不会这个玩意2333

我们cdq分治一下,先求出[1,mid]和[mid+1,r]的答案

让后我们考虑枚举j∈[mid+1,r]

对于每一个j,我们可以通过预处理出前缀min,max再二分出两个端点p1,p2满足

f(p1,j)=g(p1,j)=A[j]

f(p2,p1)=A[j]或者g(p2,p1)=A[j]

最后f(l,p2)和g(l,p2)与A[j]无关

每次统计答案可以分成这三个区间来维护

又发现,由于A[j]的单调,p2和p1肯定是单调递减的,可以用指针来维护,成功将复杂度降为O(n lg n)

#include<stdio.h>
#include<algorithm>
#define M 1000000007
#define L long long
using namespace std;
L mx[500010],mn[500010];
L sx[500010],s[500010];
L sm[500010],sn[500010];
int n;
L cdq(int l,int r){
	if(l==r) return s[l]*s[r]%M;
	int m=l+r>>1,pi=m,pj=m;
	L ans=(cdq(l,m)+cdq(m+1,r))%M;
	mx[m+1]=-M; mn[m+1]=M; 
	sm[m+1]=sn[m+1]=sx[m+1]=0;
	for(int i=m;i>=l;--i){
		mx[i]=max(mx[i+1],s[i]);
		mn[i]=min(mn[i+1],s[i]);
		sm[i]=(sm[i+1]+mx[i])%M;
		sn[i]=(sn[i+1]+mn[i])%M;
		sx[i]=(sx[i+1]+mx[i]*mn[i]%M)%M;
	}
	L rm=-M,rn=M;
	for(int j=m+1;j<=r;++j){
		rm=max(s[j],rm);
		rn=min(s[j],rn);
		while(pi>=l&&mx[pi]<rm) pi--;
		while(pj>=l&&mn[pj]>rn) pj--;
		if(pi>pj){
			ans=(ans+(m-pi)*rm%M*rn%M)%M;
			ans=(ans+rn%M*(sm[pj+1]-sm[pi+1])%M)%M;
			ans=(ans+sx[l]-sx[pj+1]+M)%M;
		} else {
			ans=(ans+(m-pj)*rm%M*rn%M)%M;
			ans=(ans+rm*(sn[pi+1]-sn[pj+1])%M)%M;
			ans=(ans+sx[l]-sx[pi+1]+M)%M;
		}
	}
	return ans;
}
int main(){
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%lld",s+i);
	printf("%lld\n",(M+cdq(1,n))%M);
}

posted @ 2017-11-16 19:32  扩展的灰(Extended_Ash)  阅读(305)  评论(0编辑  收藏  举报