正题
题目大意
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∑nr=l∑nmin{ai}∗max{ai}(i∈[l..r]))%(109+7)
解题思路
考虑分治,单独在半个内的分治下去计算,考虑如何计算跨过中点的区间。
有两种情况:
- minsminsmins和maxsmaxsmaxs全部在一边。
这时我们可以枚举一边的指针,然后因为minsminsmins和maxsmaxsmaxs都满足单调性,所以另一半边满足的区间范围也满足单调性,之间指针扫过去 - 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);
}