CF817D Imbalanced Array&P6503 [COCI2010-2011#3] DIFERENCIJA&SP10622 DIFERENC - DIFERENCIJA 做题笔记

给出 $a_i(1\le i\le n\le 10^6)$,求$$ \sum_{i=1}^{n}\sum_{j=i}^{n}(\max_{i\le k\le j}\{a_k\}-\min_{i\le l\le j}\{a_l\}) $$

解法

化简:$$ \sum_{i=1}^{n}\sum_{j=i}^{n}\max\{a_k\}- \sum_{i=1}^{n}\sum_{j=i}^{n}\min\{a_l\} $$ 分别求值。

先处理每个区间的最大值(上面公式的前半部分)。 假设当前 $a_i$ 是某个区间 $(l,r)$ 的最大值,那么可以贪心地得到当区间长度 $r-l-1$ 最大时,$a_r\ge a_i,a_l\ge a_i$。因为如果包含 $l,r$ 那么 $a_i$ 就不是区间最大了。

最小值同理。

于是问题转换成求每个 $a_i$ 向前和向后分别求出第一个比 $a_i$ 大的数和第一个比 $a_i$ 小的数。

用单调栈扫两遍解决。

注意栈空时的特判。

代码

#include <iostream>
#include <vector>
using namespace std;

typedef long long ll;
const int N=1145141;
int a[N],pma[N],sma[N],pmi[N],smi[N];
ll suma,sumi;

int main()
{
    int n;
    scanf("%d",&n);
    vector<int> ma,mi;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",a+i);
    }
    for(int i=1;i<=n;i++)
    {
        while(!ma.empty()&&a[ma.back()]<a[i])
        {
            ma.pop_back();
        }
        if(ma.empty())// 特判后赋值,下同
        {
            pma[i]=0;
        }
        else
        {
            pma[i]=ma.back();
        }
        ma.push_back(i);
        while(!mi.empty()&&a[mi.back()]>a[i])
        {
            mi.pop_back();
        }
        if(mi.empty())
        {
            pmi[i]=0;
        }
        else
        {
            pmi[i]=mi.back();
        }
        mi.push_back(i);
    }
    mi.clear();
    ma.clear();
    for(int i=n;i>0;i--)
    {
        while(!ma.empty()&&a[ma.back()]<=a[i])
        {
            ma.pop_back();
        }
        if(ma.empty())
        {
            sma[i]=n+1;
        }
        else
        {
            sma[i]=ma.back();
        }
        ma.push_back(i);
        while(!mi.empty()&&a[mi.back()]>=a[i])
        {
            mi.pop_back();
        }
        if(mi.empty())
        {
            smi[i]=n+1;
        }
        else
        {
            smi[i]=mi.back();
        }
        mi.push_back(i);
    }
    for(int i=1;i<=n;i++)
    {
        suma+=(a[i]*(i-pma[i])*(sma[i]-i));
        sumi+=(a[i]*(i-pmi[i])*(smi[i]-i));
    }
    printf("%lld",suma-sumi);
    return 0;
}
posted @ 2023-10-04 10:25  Po7ed  阅读(3)  评论(0编辑  收藏  举报  来源