分治.....
之前就了解过这种分治统计答案的算法,对于当前的区间[l,r],我们考虑过中间的那条线的区间,这种题往往都存在单调性,我们发现min和max都是随位置单调的,我们枚举左端点x,然后维护两个指针p1,p2,表示[mid+1,p1/p2]这个区间的最值大于/小于[x,mid]的最值的最远的p1/p2,那么答案就可以分3段统计,一段是[mid+1,min(p1,p2)],右端点在这一部分的区间的min和max都一样,比较容易求出。另一段是[max(p1,p2)+1,r],在这一部分的区间min和max为[mid+1,y]的最值,考虑答案的式子可以拆成:∑min*max*r-∑min*max*(l-1),那么我们就可以预处理出min*max*r和min*max的前缀和,然后就可以算出这一部分对答案的贡献。最后一段是[min(p1,p2)+1,max(p1,p2)],这个对答案的贡献和上一个和像,维护2个前缀和即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 500005 6 typedef long long LL; 7 const int mo=1000000000; 8 int n,a[maxn]; 9 LL ans,sum1[maxn][2],sum2[maxn][2],sum3[maxn][2]; 10 11 inline int read(void) 12 { 13 int x=0; 14 char ch=getchar(); 15 while (ch>‘9‘||ch<‘0‘) ch=getchar(); 16 while (ch>=‘0‘&&ch<=‘9‘) 17 { 18 x=x*10+ch-‘0‘; 19 ch=getchar(); 20 } 21 return x; 22 } 23 24 void solve(int l,int r) 25 { 26 if (l==r) 27 { 28 ans=(ans+(LL)a[l]*a[l])%mo; 29 return; 30 } 31 int mid=(l+r)>>1; 32 int mn=1e9,mx=-1; 33 sum1[mid][0]=sum1[mid][1]=0; 34 sum2[mid][0]=sum2[mid][1]=0; 35 sum3[mid][0]=sum3[mid][1]=0; 36 for (int i=mid+1;i<=r;i++) 37 { 38 mn=min(mn,a[i]); 39 mx=max(mx,a[i]); 40 sum1[i][0]=(LL)mn*mx%mo*i%mo;sum1[i][1]=(LL)mn*mx%mo; 41 sum2[i][0]=(LL)mn*i%mo;sum2[i][1]=mn; 42 sum3[i][0]=(LL)mx*i%mo;sum3[i][1]=mx; 43 } 44 for (int i=mid+2;i<=r;i++) 45 { 46 (sum1[i][0]+=sum1[i-1][0])%=mo;(sum1[i][1]+=sum1[i-1][1])%=mo; 47 (sum2[i][0]+=sum2[i-1][0])%=mo;(sum2[i][1]+=sum2[i-1][1])%=mo; 48 (sum3[i][0]+=sum3[i-1][0])%=mo;(sum3[i][1]+=sum3[i-1][1])%=mo; 49 } 50 mn=1e9,mx=-1; 51 int t1=a[mid+1],t2=a[mid+1]; 52 int p1=mid,p2=mid; 53 for (int i=mid;i>=l;i--) 54 { 55 mn=min(mn,a[i]);mx=max(mx,a[i]); 56 while (t1>=mn&&p1<r) p1++,t1=min(t1,a[p1+1]); 57 while (t2<=mx&&p2<r) p2++,t2=max(t2,a[p2+1]); 58 int tmp=min(p1,p2); 59 LL w=(LL)(mid+2-i+tmp-i+1)*(tmp-mid)/2;w%=mo; 60 ans=(ans+w*mn%mo*mx%mo)%mo; 61 tmp=max(p1,p2)+1; 62 w=(sum1[r][0]-sum1[tmp-1][0]+mo)%mo; 63 w=(w-(sum1[r][1]-sum1[tmp-1][1]+mo)%mo*(i-1)%mo+mo)%mo; 64 ans=(ans+w)%mo; 65 if (p1<=p2) 66 { 67 w=(sum2[p2][0]-sum2[p1][0]+mo)%mo*mx%mo; 68 w=(w-(sum2[p2][1]-sum2[p1][1]+mo)%mo*(i-1)%mo*mx%mo+mo)%mo; 69 ans=(ans+w)%mo; 70 } 71 else 72 { 73 w=(sum3[p1][0]-sum3[p2][0]+mo)%mo*mn%mo; 74 w=(w-(sum3[p1][1]-sum3[p2][1]+mo)%mo*(i-1)%mo*mn%mo+mo)%mo; 75 ans=(ans+w)%mo; 76 } 77 } 78 solve(l,mid); 79 solve(mid+1,r); 80 } 81 82 int main() 83 { 84 n=read(); 85 for (int i=1;i<=n;i++) a[i]=read(); 86 solve(1,n); 87 printf("%lld\n",ans); 88 return 0; 89 }
时间: 2024-09-28 16:13:53