ebisukeプログラミング初心者脱出黙示録

30歳を過ぎてから始めたプログラミングと競プロの記録。Pythonで取り組んでいます。Arduinoで電子工作も

AtCoder-ABC186 D - Sum of difference【Python解答例】

AtCoderパナソニックプログラミングコンテストAtCoder Beginner Contest186)のD問題について、コンテストでは解けなかった問題を勉強していきます。
Panasonic Programming Contest (AtCoder Beginner Contest 186) - AtCoder

AtCoder Beginner Contest186 D - Sum of difference

D - Sum of difference

問題文

N個の整数A1,…,ANが与えられます。
1 ≤ i < j ≤ Nを満たす全てのi,jの組についての|Ai−Aj|の和を求めてください。
すなわち、N−1∑i=1 N∑j=i+1 |Ai−Aj|を求めてください。

制約

・2≤N≤2×10^5
・|Ai|≤10^8
・Aiは整数である。

解答例

n = int(input())

a = list(map(int, input().strip().split()))
a.sort()

ans = 0
sum_a = a[0]
for j in range(1,n):
    ans += j * a[j] - sum_a
    sum_a += a[j]

print(ans)

解説

youtubeの公式解説で勉強した内容です。

整数のリストaは入力を受け取ったあとでソートしています。
これによりAj - Aiは正の整数となるので絶対値をとる必要がなくなります。

ここから先の計算は、問題文通り2重ループとするとTLEになります(NG例として載せます)ので、jの1重ループを回します。
ans変数はAj - Aiを足し合わせた解答となる変数です。
sum_a 変数はa[j-1]までの累積和です。
j = 3のとき、[i, j]の組み合わせは[1, 3]と[2, 3]の2通り考えられます。
よってAj - Aiにおいて、Aj = a[j]×jとなりAiはj-1までの累積和になります。
この計算をNまで繰り返すことでans変数に求める値が格納されました。

NG例

n = int(input())

a = list(map(int, input().strip().split()))

ans = 0
for i in range(n-1):
    for j in range(i+1,n):
        ans += abs(a[i] - a[j])

print(ans)

問題文通りの2重ループを回したプログラムです。
こんな簡単なわけないよな…と思いながら提出しましたが、やはりNGでした。


D問題は中央値や平均値など使えるか考えましたがピントが合っていなかったです。
簡単に紙に書き出してみると着想を得ることができるかも、という印象を受けましたので次回からは試してみたいです。


パナソニックプログラミングコンテスト(ABC186)の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com