CS Academy Subarray Medians

リンク : https://csacademy.com/contest/archive/task/subarray-medians/

問題概要

長さNの数列が与えられる。(1<=i<=j<=N かつ j-i=0 mod2)のすべてのi,jに関して[i,j]の中央値をmとしたとき、ijmの総和を求めよ。

解説

最初、iを決めて、前から順にBIT上のa[j]に1を足して、二部探索してO(N2 logn)で求めたら、TLEしてしまった。ここで違うアプローチを考える。すべてのi,jの中央値を考えるのではなく、iがmとして取られるときの総和を求めることにする(割とこの考えは使う)。i<=jのとき、[i,j]に(a[i]より大きい個数)-(a[i]より小さい個数)をdifとする。d[dif]+=jをする。次にj<=iを見た時に、[j,i]に(a[i]より大きい個数)-(a[i]より小さい個数)をdifとすると、d[-dif]ja[i]をとることによってj番目から始まる区間で、中央値がi番目となるときをすべて考えることができる。

LL n, ans, a[11000], d[11000];
int main() {
    cin >> n;
    rep(i, n) {
        cin >> a[i];
    }
    rep(i, n) {
        rep(j, 11000)d[j] = 0;
        LL dif = 5000;
        for (int j = i; j >=0; j--) {
            if (a[i] > a[j])dif++;
            else dif--;
            if (dif <= 10000 && dif >= 0)d[dif] += (j + 1);
        }
        dif = 5000;
        for (int j = i; j < n; j++) {
            if (a[i] >= a[j])dif--;
            else dif++; 
            if (dif <= 10000 && dif >= 0)ans += a[i] * d[dif] * (j + 1);
        }
    }
    cout << ans << endl;
    return 0;
}