公式

F - Double Sum 3 解説 by sounansya


黒板にいくつかの整数が書かれている場合に、操作回数を最小とするために \(l,r\)\(r-l\) が極大になるように選べば良いです。つまり、

  • \(l-1\) は黒板に書かれていない。
  • \(l\) 以上 \(r\) 以下の整数はどれも黒板に書かれている。
  • \(r+1\) は黒板に書かれていない。

これらの \(3\) つの条件を満たす \((l,r)\) を選び、順番に黒板から消していけば良いです。

この事実を踏まえて問題を解いていきます。

整数 \(1\le c\le N\) を固定し、\(f(L,R)\) の計算過程で \(l=c\) とする操作が現れるような整数の組 \((L,R)\) の個数を \(g(c)\) とします。すると、求める答えは \(\displaystyle \sum_{c=1}^Ng(c)\) と一致することが分かります。以降は各 \(c\) に対し \(g(c)\) を求めることを考えます。

\(l=c\) とする操作をする条件は、上の考察により \(S=\{A_L,A_{L+1},\ldots,A_R\}\) に対し以下の \(2\) つを共に満たすことであることが分かります。

  • \(c-1\notin S\)
  • \(c\in S\)

よって、 \(g(c)\)\(c-1\notin S\) を満たす \((L,R)\) の組の個数から \(c-1\notin S\) かつ \(c\notin S\) を満たす \((L,R)\) の組の個数を引いた値と一致します。

ここで、 \(G_c\)\(A_i=c\) を満たす \(i\) の集合とすると、 \(c\notin S\)\(L\) 以上 \(R\) 以下の整数が全て \(G_c\) に属さないことと同値です。この条件を満たす \((L,R)\) の組は \(G_c=\{X_1,X_2,\ldots,X_{|G_c|}\}\) \((X_1<X_2<\ldots<X_{|G_c|}),\) \(X_0=0,\) \(X_{|G_c|+1}=N+1\) として \(\displaystyle \sum_{k=0}^{|G_c|}\frac{(X_{k+1}-X_k)(X_{k+1}-X_k-1)}2\) 通りです。 \(c-1\notin S\) かつ \(c\notin S\) を満たす \((L,R)\) の組の個数も同様にして求めることができます。

これらの計算をすることで各 \(c\) に対する \(g(c)\) の値が求まるので、それらの総和を計算することで答えを求めることができます。計算量は \(O(N)\) です。

なお、以下では可視性を上げるために \(O(N\log N)\) 時間の実装を載せています。

実装例(Python3)

n = int(input())
a = list(map(int, input().split()))
g = [[] for i in range(n + 1)]
for i in range(n):
    g[a[i] - 1].append(i)

def f(x):
    res = 0
    for i in range(1, len(x)):
        c = x[i] - x[i - 1]
        res += c * (c - 1) // 2
    return res

ans = 0
for i in range(1, n + 1):
    ans += f([-1] + g[i] + [n])
    ans -= f([-1] + sorted(g[i - 1] + g[i]) + [n])
print(ans)

投稿日時:
最終更新: