COCI2014/2015 Contest#2 F Solution

Description

給出數列A,求ni=1nj=imaxjk=iminjk=i(ji+1)

Solution

怎麼看都像數據結構或者貪心的題目,然而正解卻是分治。
這個分治就是分而治之,並沒有歸併。
首先對於區間[l,r],mid=l+r/2 ,我們在區間[l,mid] 裏枚舉一個點,我們可以求出lMx=maxmidi=l 以及IMn=minmidi=l (只要O(n) 的從mid開始向l枚舉即可),那麼設當前左邊枚舉到i ,然後對於區間[mid+1,r] ,我們可以把它分段:
區間[mid+1,L) 表示maxLi=l =lMx並且minLi=1 =lMn
我們可以輕鬆的計算其值。
然後是區間[L,R) 表示maxLi=l =lMx或者minLi=1 =lMn,這兩個不會同時滿足因爲同時滿足的區間會併到第一種情況那裏,然後無論是maxLi=l 還是minLi=1 都單調的。這個我們可以通過巧妙的前綴和搞定。
最後是區間[R,r] 表示maxLi=l >lMx並且minLi=1

#include<iostream>
#include<algorithm>
using namespace std;
const int INF=(unsigned)-1>>1,M=1e5+5,P=1e9;
int A[M],n,sMx[M],sMn[M],cMx[M],cMn[M],cM[M],sM[M];
inline void rd(int &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
inline void Max(int &a,int b){if(a<b)a=b;}
inline void Min(int &a,int b){if(a>b)a=b;}
inline void Mod_add(int &a,int b){if((a+=b)>=P)a-=P;}
inline int dis(int l1,int l2){return 1ll*((l2-l1+1)*(l1+l2)>>1)%P;}
int solve(int l,int r){
    if(l==r)return 1ll*A[l]*A[l]%P;
    int mid=l+r>>1,ans;if((ans=solve(l,mid)+solve(mid+1,r))>=P)ans-=P;
    for(int i=mid+1,rMx=0,rMn=INF,len;len=i-mid,i<=r;++i){
        Max(rMx,A[i]),Min(rMn,A[i]),sMx[i]=rMx,sMn[i]=rMn;
        cMx[i]=1ll*rMx*len%P,cMn[i]=1ll*rMn*len%P;
        cM[i]=1ll*len*rMx*rMn%P,sM[i]=1ll*rMx*rMn%P;
    }
    for(int i=r-1;i>mid;--i){
        Mod_add(cMx[i],cMx[i+1]),Mod_add(cMn[i],cMn[i+1]);
        Mod_add(cM[i],cM[i+1]),Mod_add(sM[i],sM[i+1]);
        Mod_add(sMx[i],sMx[i+1]),Mod_add(sMn[i],sMn[i+1]);
    }
    for(int i=mid,px=mid+1,pn=mid+1,lMx=0,rMx=0,lMn=INF,rMn=INF;i>=l;--i){
        Min(lMn,A[i]),Max(lMx,A[i]);
        for(;px<=r&&(rMx=max(A[px],rMx))<=lMx;++px);
        for(;pn<=r&&(rMn=min(A[pn],rMn))>=lMn;++pn);
        int L=min(pn,px),R=max(pn,px);
        Mod_add(ans,1ll*lMx*lMn%P*dis(mid-i+2,L-i)%P);
        Mod_add(ans,(cM[R]+1ll*sM[R]*(mid-i+1))%P);
        if(L==pn)Mod_add(ans,((cMn[pn]-cMn[px]+1ll*(sMn[pn]-sMn[px])*(mid-i+1))%P+P)%P*lMx%P);
        else Mod_add(ans,((cMx[px]-cMx[pn]+1ll*(sMx[px]-sMx[pn])*(mid-i+1))%P+P)%P*lMn%P);
    }
    return ans;
}
int main(){
    cin>>n;for(int i=1;i<=n;++i)rd(A[i]);
    cout<<solve(1,n)<<endl;
    return 0;
}

orz Leefir的數形結合套線段樹,orz他的神奇的三角形,orz ShinFeb的5K的分類討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章