3745: [Coci2015]Norma

来源:互联网 发布:程序员 bug 编辑:程序博客网 时间:2024/06/06 07:51

知道用分治以后,其实这题就不用再看题解了。

考虑i∈[l,mid],j∈[mid,r]时对答案的贡献。

记录从mid往左、往右时最小值、最大值的变化情况,将如图所示。

黄色表示最大值,蓝色表示最小值,然后绿色表示黄色和蓝色重合。。。

统计时,指针i从mid向左移动,j、k从mid向右移动,保证Min(mid...j)大于等于Min(i...mid)、Max(mid...k)≤Max(i...mid)。

对于每个i,均可分成三段统计,共下图两种情况。

对右边进行前缀和,S00、S01、S02表示蓝色、黄色、蓝黄相乘的和,S10[j]、S11[j]、S12[j]表示每个点(蓝色、黄色、蓝黄相乘)后乘上j-mid+1。具体见代码。

#include<cstdio>#include<iostream>#include<cmath>#include<algorithm>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define sqr(x) ((x)*(x))#define G getchar()#define LL long long#define pll pair<LL,LL>#define mkp make_pair#define X first#define Y second#define N 500005#define M 1000000000LL n,a[N],ans,Max[N],Min[N],mmp[N],S00[N],S01[N],S02[N],S10[N],S11[N],S12[N];int read(){int x=0;char ch=G;for(;ch<48||ch>57;ch=G);for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;return x;}LL add(LL x,LL y){LL rtn=x+y;if(rtn>=M)rtn-=M;return rtn;}LL sub(LL x,LL y){LL rtn=x-y;if(rtn<0)rtn+=M;return rtn;}LL mul(LL x,LL y){return x*y%M;}LL cal(LL x,LL y){return ((x+y)*(x-y+1)>>1)%M;}void cdq(LL l,LL r){if(l>r)return;if(l==r){ans=add(ans,mul(a[l],a[l]));return;}LL mid=l+r>>1,i,j,k;Min[mid]=Max[mid]=S00[mid]=S01[mid]=S02[mid]=S10[mid]=S11[mid]=S12[mid]=a[mid];mmp[mid]=mul(a[mid],a[mid]);per(i,mid-1,l)mmp[i]=mul(Max[i]=max(Max[i+1],a[i]),Min[i]=min(Min[i+1],a[i]));rep(i,mid+1,r){mmp[i]=mul(Max[i]=max(Max[i-1],a[i]),Min[i]=min(Min[i-1],a[i]));S00[i]=add(S00[i-1],Min[i]);S01[i]=add(S01[i-1],Max[i]);S02[i]=add(S02[i-1],mmp[i]);S10[i]=add(S10[i-1],mul(i-mid+1,Min[i]));S11[i]=add(S11[i-1],mul(i-mid+1,Max[i]));S12[i]=add(S12[i-1],mul(i-mid+1,mmp[i]));}per(i,j=k=mid,l){while(j<r&&Min[j+1]>=Min[i])++j;while(k<r&&Max[k+1]<=Max[i])++k;if(j<k){ans=add(ans,mul(mmp[i],cal(j-i+1,mid-i+1)));ans=add(ans,mul(Max[i],add(sub(S10[k],S10[j]),mul(sub(S00[k],S00[j]),mid-i))));if(k<r)ans=add(ans,add(sub(S12[r],S12[k]),mul(sub(S02[r],S02[k]),mid-i)));}else if(j>k){ans=add(ans,mul(mmp[i],cal(k-i+1,mid-i+1)));ans=add(ans,mul(Min[i],add(sub(S11[j],S11[k]),mul(sub(S01[j],S01[k]),mid-i))));if(j<r)ans=add(ans,add(sub(S12[r],S12[j]),mul(sub(S02[r],S02[j]),mid-i)));}else{ans=add(ans,mul(mmp[i],cal(j-i+1,mid-i+1)));if(k<r)ans=add(ans,add(sub(S12[r],S12[k]),mul(sub(S02[r],S02[k]),mid-i)));}}cdq(l,mid-1);cdq(mid+1,r);}int main(){int i;n=read();rep(i,1,n)a[i]=read();cdq(1LL,n);printf("%lld\n",ans);return 0;}

又把膜数打错了鈤。


原创粉丝点击