3745: [Coci2015]Norma 分治

题解:

分治的一般套路,递归处理左右区间,然后算出过 mid m i d 的答案,然后对于怎么算,一般都是分类讨论一下,对于这道题目,枚举左端点 i i <script type="math/tex" id="MathJax-Element-54">i</script>,然后根据最大最小值的位置进行分类讨论和预处理,推一大堆式子,具体怎么推可以看CQzhangyu的博客。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const LL mod=1e9,inf=1e8+10;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n;LL v[Maxn],ans=0;
LL t1[Maxn],t2[Maxn],t3[Maxn],t4[Maxn],t5[Maxn],t6[Maxn];
LL Sum(LL l,LL r){return ((l+r)*(r-l+1)/2LL)%mod;}
void solve(int l,int r)
{
    if(l==r){ans=(ans+v[l]*v[l])%mod;return;}
    int mid=l+r>>1;
    solve(l,mid),solve(mid+1,r);
    t1[mid]=t2[mid]=t3[mid]=t4[mid]=t5[mid]=t6[mid]=0;
    LL mn=inf,mx=-inf;
    for(LL i=mid+1;i<=r;i++)
    {
        mn=min(mn,v[i]);mx=max(mx,v[i]);
        t1[i]=(t1[i-1]+mn*i%mod)%mod;t2[i]=(t2[i-1]+mn)%mod;
        t3[i]=(t3[i-1]+mx*i%mod)%mod;t4[i]=(t4[i-1]+mx)%mod;
        t5[i]=(t5[i-1]+mn*mx%mod*i%mod)%mod;
        t6[i]=(t6[i-1]+mn*mx%mod)%mod;
    }
    mn=inf,mx=-inf;LL a=mid,b=mid;
    LL tmp;
    for(LL i=mid;i>=l;i--)
    {
        tmp=ans;
        mn=min(mn,v[i]);mx=max(mx,v[i]);
        while(a<r&&v[a+1]>=mn)a++;while(b<r&&v[b+1]<=mx)b++;
        if(a<b)
        {
            if(a>=mid+1)ans=(ans+mn*mx%mod*Sum(mid-i+2,a-i+1)%mod)%mod;
            ans=(ans+mx*((t1[b]-t1[a]+mod)%mod-(i-1)%mod*((t2[b]-t2[a]+mod)%mod)%mod+mod)%mod)%mod;
            ans=(ans+((t5[r]-t5[b]+mod)%mod-(i-1)%mod*((t6[r]-t6[b]+mod)%mod)%mod+mod)%mod)%mod;
        }
        else
        {
            if(b>=mid+1)ans=(ans+mn*mx%mod*Sum(mid-i+2,b-i+1)%mod)%mod;
            if(a!=b)ans=(ans+mn*((t3[a]-t3[b]+mod)%mod-(i-1)%mod*((t4[a]-t4[b]+mod)%mod)%mod+mod)%mod)%mod;
            ans=(ans+((t5[r]-t5[a]+mod)%mod-(i-1)%mod*((t6[r]-t6[a]+mod)%mod)%mod+mod)%mod)%mod;
        }
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)v[i]=read();
    solve(1,n);
    printf("%lld",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值