zoukankan      html  css  js  c++  java
  • bzoj 3745 [Coci2015]Norma

    题目的大意是求一个数列中任意一个区间的长度乘上区间最大值和最小值求和。

    我们二分来做这个题,每次递归处理,然后我们只需统计所有跨过中点的区间的贡献即可。

    我们枚举[l,mid]区间里的每一个数a[i] (l<=i<=mid),因为无论最大值和最小值随着区间扩大有单调性,所以我们维护两个指针,分别记录右面区间最远的能够到达的距离,满足[mid+1,p1] [mid+1,p2] 的区间最大/(最小值) 小于/(大于) 等于 [i,mid]的最大(最小)值。

    然后我们分三块来统计,[i,min(p1,p2)]内所有的区间  , i到[max(p1,p2),r] 的所有区间  ,   i到[min(p1,p2),max(p1,p2)]所有区间,自己推一下式子就行啦。(中间少取了两次模,wa了好多次,感觉自己好蠢。。。。。。) ——by VANE

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9;
    const int N=5e5+5;
    void add(ll &x,ll y) {x=((x+y)%mod+mod)%mod;}
    ll getsum(int l,int r){return 1ll*(l+r)*(r-l+1)/2%mod;}
    ll f1[N],f2[N],f3[N],f4[N],a[N],n,ans,f5[N],f6[N];
    ll mn[N],mx[N];
    void solve(int l,int r)
    {
        if(l==r) {add(ans,a[l]*a[l]%mod);return;}
        int mid=l+r>>1;
        solve(l,mid);solve(mid+1,r);
        mn[mid]=mod;mx[mid]=-mod;
        f1[r+1]=0;f2[r+1]=0;
        f3[mid]=0;f4[mid]=0;
        f5[mid]=0;f6[mid]=0;
        int p1,p2;
        for(int i=mid+1;i<=r;++i)
        {
            mn[i]=min(mn[i-1],a[i]);mx[i]=max(mx[i-1],a[i]);
            f3[i]=f3[i-1]+i*mx[i];
            f4[i]=f4[i-1]+i*mn[i];
            f3[i]%=mod;f4[i]%=mod;
            f5[i]=f5[i-1]+mx[i];f5[i]%=mod;
            f6[i]=f6[i-1]+mn[i];f6[i]%=mod;
        }
        for(int i=r;i>=mid+1;--i)
        {
            f1[i]=f1[i+1]+mx[i]*mn[i]%mod*i%mod;
            f2[i]=f2[i+1]+mx[i]*mn[i]%mod;
            f1[i]%=mod;f2[i]%=mod;
        }
        p1=mid+1;p2=mid+1;
        ll mxl=-mod,mnl=mod;
        for(int i=mid;i>=l;--i)
        {
            mxl=max(mxl,a[i]);
            mnl=min(mnl,a[i]);
            while(p2<=r&&mn[p2]>=mnl) p2++;
            while(p1<=r&&mx[p1]<=mxl) p1++;
            p1--;p2--;
            add(ans,getsum(mid+1-i+1,min(p1,p2)-i+1)*mxl%mod*mnl%mod);
            add(ans,f1[max(p1,p2)+1]-f2[max(p1,p2)+1]*(i-1)%mod);
            if(p1<=p2)
                add(ans,mnl*(f3[p2]-f3[p1]-1ll*(i-1)*(f5[p2]-f5[p1])%mod));
            else
                add(ans,mxl*(f4[p1]-f4[p2]-1ll*(i-1)*(f6[p1]-f6[p2])%mod));
        }
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;++i) scanf("%lld",a+i);
        solve(1,n);
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    phpexcel 字符串转码
    thinkphp 3.2 linux二级目录安装
    linux 系统、命令、软件
    thinkphp3.2和phpexcel导入
    苹果手机微信分享代码失效
    thinkphp3.2与phpexcel带图片生成 完美案例
    thinkphp3.2与phpexcel基础生成
    thinkphp 3.2加载类
    thinkphp 3.2与phpexcel
    thinkphp 导出exl功能
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8067431.html
Copyright © 2011-2022 走看看