jzoj5231-序列问题【分治】
生活随笔
收集整理的這篇文章主要介紹了
jzoj5231-序列问题【分治】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目大意
nnn個數字,求
(∑l=1n∑r=lnmin{ai}?max{ai}(i∈[l..r]))%(109+7)(\sum_{l=1}^n\sum_{r=l}^nmin\{a_i\}*max\{a_i\}(i\in [l..r]))\%(10^9+7)(l=1∑n?r=l∑n?min{ai?}?max{ai?}(i∈[l..r]))%(109+7)
解題思路
考慮分治,單獨在半個內的分治下去計算,考慮如何計算跨過中點的區間。
有兩種情況:
這時我們可以枚舉一邊的指針,然后因為minsminsmins和maxsmaxsmaxs都滿足單調性,所以另一半邊滿足的區間范圍也滿足單調性,之間指針掃過去
枚舉右邊指針,然后兩個指針在左邊表示滿足的區間的范圍限制。之后用前綴和優化計算
時間復雜度O(nlogn)O(n\ log\ n)O(n?log?n)
codecodecode
#include<cstdio> #include<algorithm> #define N 500010 #define ll long long using namespace std; const ll XJQ=1e9+7; ll ans,n,m; ll mi[N],mx[N],a[N],sum[N]; void dg(ll l,ll r) {ll j,k;if(l==r){(ans+=a[l]*a[l]%XJQ)%=XJQ;return;}if(l>r) return;ll mid=(l+r)/2;mi[mid+1]=mx[mid+1]=a[mid+1];mi[mid]=mx[mid]=a[mid];for(ll i=mid+2;i<=r;i++)mi[i]=min(a[i],mi[i-1]),mx[i]=max(a[i],mx[i-1]);for(ll i=mid-1;i>=l;i--)mi[i]=min(a[i],mi[i+1]),mx[i]=max(a[i],mx[i+1]);j=mid;for(ll i=mid+1;i<=r;i++){while(mi[j]>=mi[i]&&mx[j]<=mx[i]&&j>=l) j--;ans=(ans+mi[i]*mx[i]%XJQ*(mid-j)%XJQ)%XJQ;}j=mid+1;for(ll i=mid;i>=l;i--){while(mi[j]>=mi[i]&&mx[j]<=mx[i]&&!(mi[j]==mi[i]&&mx[j]==mx[i])&&j<=r) j++;ans=(ans+mi[i]*mx[i]%XJQ*(j-mid-1)%XJQ)%XJQ;}sum[l-1]=0;for(ll i=l;i<=mid;i++)sum[i]=sum[i-1]+mi[i];j=mid;k=mid;for(ll i=mid+1;i<=r;i++){while(mx[j]<mx[i]&&j>=l) j--;while(mi[k]>=mi[i]&&k>=l) k--;if(j+1<=k) ans=(ans+(sum[k]-sum[j])%XJQ*mx[i]%XJQ)%XJQ;}for(ll i=l;i<=mid;i++)sum[i]=sum[i-1]+mx[i];j=mid;k=mid;for(ll i=mid+1;i<=r;i++){while(mx[j]<=mx[i]&&j>=l) j--;while(mi[k]>mi[i]&&k>=l) k--;if(k+1<=j) ans=(ans+(sum[j]-sum[k])%XJQ*mi[i]%XJQ)%XJQ;}dg(l,mid);dg(mid+1,r); } int main() {freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);dg(1,n);printf("%lld",ans); }總結
以上是生活随笔為你收集整理的jzoj5231-序列问题【分治】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jzoj5230-队伍统计【状压dp】
- 下一篇: 欢乐纪中某B组赛【2019.1.27】