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);
}