题解:AT_abc390_f [ABC390F] Double Sum 3

· · 题解

根据题目描述,可以发现 f(L,R) 其实就是 A_L,A_{L+1}\dots A_R 中的数组成的极长值域连续段数。

我们考虑扫描右端点 r,同时维护每个左端点的 f(l,r)

每次左端点右移,那么 f(l,r) 会变成 f(l,r+1),其实就是添加一个数 A_{r+1},那么会造成什么影响呢?

假设 A_{r+1} 之前未出现过,那么添加之后:

那么我们开一个数组 pre_i 代表数字 i 上一次出现的位置,每次加入数字 x=A_{r} 时,记 a=\min(pre_{x-1},pre_{x+1}),b=\max(pre_{x-1},pre_{x+1})

做法已经呼之欲出了,从左向右扫描右端点的同时维护 sum=\sum\limits_{l=1}^rf(l,r) ,同时用 ans 进行累加。

#include <bits/stdc++.h>
#define LL long long
using namespace std;

inline LL read()
{
    LL x = 0,f = 1;char ch = getchar();
    while(!isdigit(ch)) (ch == '-') && (f = -1),ch = getchar();
    while(isdigit(ch)) x = x*10+ch-48,ch = getchar();
    return x*f;
}

const int N = 3e5+5;
int a[N],pre[N];

int main()
{
    int n = read();
    LL ans = 0,sum = 0;
    for (int i = 1;i <= n;i++)
    {
        a[i] = read();
        int x = max(pre[a[i]-1],pre[a[i]]),y = max(pre[a[i]+1],pre[a[i]]);
        if (x > y) swap(x,y);
        sum = sum+i-y-(x-pre[a[i]]),ans += sum;
        pre[a[i]] = i;
    }
    cout << ans;
    return 0;
}