洛谷SP22343 NORMA2 - Norma(分治,前缀和)

洛谷题目传送门

这题推式子恶心。。。。。

考虑分治,每次统计跨过mid的所有区间的答案和。imid1l枚举,统计以i为左端点的所有区间。

我们先维护好[i,mid]区间内最小值mn和最大值mx。我们可以想到,对于某一个左端点,它的右端点j在一定的范围内,最小值和最大值都不会变。这里就看到一些可以重复利用并快速计算的信息了。

维护两个指针p,q,分别表示[mid+1,r]内元素值第一个小于mn/大于mx的位置,那么j=mid+1rans[i,j]就可以分成三类讨论。暂时假设p<q

j[mid+1,p1]时,区间的最值不变,都是mn,mx,直接高斯求和

ansmnmxj=mid+1p1ji+1

j[p,q1]时,区间最大值不变,但最小值取的是[mid+1,j]里的了。预处理mid+1r的前缀最小值minj,同时记录minjminjj的前缀和(pq同理)

ansmxj=pq1minj(ji+1)

ansmxj=pq1minjj+mx(1i)j=pq1minj

j[q,r]时,最值和mn,mx无关了,记录minjmaxjminjmaxjj的前缀和

ansj=qrminjmaxj(ji+1)

ansj=qrminjmaxjj+(1i)j=qrminjmaxj

容易发现mn,mx,p,q都是单调移动的,那么就大功告成啦!

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG LL//常数大也无所谓了
#define G if(++ip==ie)fread(ip=buf,1,N,stdin)
#define A(V) (ans+=V)%=YL
using namespace std;
const LL N=1<<19,YL=1e9;
char buf[N],*ie=buf+N,*ip=ie-1;
LL ans,a[N],mns[N],mxs[N],mnj[N],mxj[N],mms[N],mmj[N];
inline LL in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
inline LL S(R l,R r){//高斯求和
    return (l+r)*(r-l+1)/2%YL;
}
void solve(R l,R r){
    if(l==r){A(a[l]*a[l]);return;}
    R m=(l+r)>>1,i,j,p,q,mn=YL,mx=0;
    solve(l,m);solve(m+1,r);
    mns[m]=mxs[m]=mnj[m]=mxj[m]=mms[m]=mmj[m]=0;
    for(j=m+1;j<=r;++j){//预处理,变量名不解释
        mn=min(mn,a[j]);mx=max(mx,a[j]);
        mns[j]=(mns[j-1]+mn)%YL;
        mxs[j]=(mxs[j-1]+mx)%YL;
        mnj[j]=(mnj[j-1]+mn*j)%YL;
        mxj[j]=(mxj[j-1]+mx*j)%YL;
        mms[j]=(mms[j-1]+mn*mx)%YL;
        mmj[j]=(mmj[j-1]+mn*mx%YL*j)%YL;
    }
    mn=YL;mx=0;
    for(p=q=m+1,i=m;i>=l;--i){//计算答案
        mn=min(mn,a[i]);mx=max(mx,a[i]);
        while(p<=r&&mn<a[p])++p;//单调移动
        while(q<=r&&mx>a[q])++q;
        if(p<q){
            A(mn*mx%YL*S(m-i+2,p-i));//注意做减法的都要加一下模数
            A(mx*(mnj[q-1]-mnj[p-1]+YL)+mx*(mns[q-1]-mns[p-1]+YL)%YL*(1-i+YL));
            A(mmj[r]-mmj[q-1]+(mms[r]-mms[q-1]+YL)*(1-i+YL));
        }
        else{
            A(mn*mx%YL*S(m-i+2,q-i));
            A(mn*(mxj[p-1]-mxj[q-1]+YL)+mn*(mxs[p-1]-mxs[q-1]+YL)%YL*(1-i+YL));
            A(mmj[r]-mmj[p-1]+(mms[r]-mms[p-1]+YL)*(1-i+YL));
        }
    }
}
int main(){
    R n=in();
    for(R i=1;i<=n;++i)a[i]=in();
    solve(1,n);
    printf("%lld\n",ans);
    return 0;
}
posted @   Flash_Hu  阅读(659)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
剑桥
17:14发布
剑桥
17:14发布
5°
西风
7级
空气质量
相对湿度
34%
今天
多云
-3°/5°
周六
-1°/3°
周日
-2°/7°