P10173题解
P10173 maxiMINImax
题解
感觉还是比较套路的,而且不需要笛卡尔树,连我都能做出来。
这种区间 \(\min,\max\) 的题不难想到单调栈,我们可以 \(O(n)\) 处理出有几个区间的最小/大值为 \(a_i\),记为 \(ln_i,lx_i\)。然后推一下式子,写成标准形式,即 \(\sum\limits_{i<j<k}ln_j\times lx_i\times lx_k\times (a_j-a_i)(a_j-a_k)\) 。
最后那个东西显然可以拆开,变成 \(a_i^2-a_ia_j-a_ia_k+a_ja_k\)。
可以用权值树状数组求出 \(\sum\limits_{i=1}^{x-1}lx_i,\sum\limits_{i=1}^{x-1}lx_ia_i,\sum\limits_{i=x+1}^nlx_i,\sum\limits_{i=x+1}^nlx_ia_i\),简记为 \(l1_x,l2_x,r1_x,r2_x\),则答案为 \(\sum\limits_{i=1}^nln_i\times(a_i^2\times l1_i\times r1_i-a_i\times l2_i\times r1_i-a_i\times l1_i\times r2_i+l2_i\times r2_i)\),即可 \(O(n)\) 统计。
代码:
/*
* @Author: operator_
* @Date: 2024-02-18 15:43:22
* @Last Modified by: operator_
* @Last Modified time: 2024-02-18 17:16:35
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd() {
int s=0,m=0;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')m=1;ch=getchar();}
while( isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
}
const int M=9712176;
int n,a[1000005],ans,st1[1000005],top1,st2[100005],top2;
int lmin[1000005],rmin[1000005],lmax[1000005],rmax[1000005];
int lenmin[1000005],lenmax[1000005],l1[1000005],l2[1000005],r1[1000005],r2[1000005];
struct Binary_Indexed_Tree {
int t[1000005];
int lb(int x) {return x&-x;}
int sum(int x) {int s=0;for(int i=x;i;i-=lb(i)) s=(s+t[i])%M;return s;}
void add(int x,int k) {for(int i=x;i<=n;i+=lb(i)) t[i]=(t[i]+k)%M;}
}t1,t2;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++) {
while(top1&&a[st1[top1]]>a[i]) top1--;
lmin[i]=st1[top1];st1[++top1]=i;
while(top2&&a[st2[top2]]<a[i]) top2--;
lmax[i]=st2[top2];st2[++top2]=i;
}
st1[top1=0]=st2[top2=0]=n+1;
for(int i=n;i>=1;i--) {
while(top1&&a[st1[top1]]>a[i]) top1--;
rmin[i]=st1[top1];st1[++top1]=i;
while(top2&&a[st2[top2]]<a[i]) top2--;
rmax[i]=st2[top2];st2[++top2]=i;
}
for(int i=1;i<=n;i++)
lenmin[i]=(i-lmin[i])*(rmin[i]-i)%M,lenmax[i]=(i-lmax[i])*(rmax[i]-i)%M;
for(int i=1;i<=n;i++) {
l1[i]=t1.sum(a[i]),l2[i]=t2.sum(a[i]);
t1.add(a[i],lenmax[i]);t2.add(a[i],lenmax[i]*a[i]%M);
}
for(int i=1;i<=n;i++) t1.t[i]=t2.t[i]=0;
for(int i=n;i>=1;i--) {
r1[i]=t1.sum(a[i]),r2[i]=t2.sum(a[i]);
t1.add(a[i],lenmax[i]);t2.add(a[i],lenmax[i]*a[i]%M);
}
for(int i=1;i<=n;i++) {
ans=(ans+a[i]*a[i]%M*l1[i]%M*r1[i]%M*lenmin[i]%M)%M;
ans=(ans-a[i]*l2[i]%M*r1[i]%M*lenmin[i]%M+M)%M;
ans=(ans-a[i]*l1[i]%M*r2[i]%M*lenmin[i]%M+M)%M;
ans=(ans+l2[i]*r2[i]%M*lenmin[i]%M)%M;
}
cout<<ans;
return 0;
}
本文来自博客园,作者:operator,转载请注明原文链接:https://www.cnblogs.com/operator-/p/18019856 ♪(^∀^●)ノシ