C - 気温の均し / Smoothing the Temperature Editorial by admin
GPT 5.2 High概要
長さ \(K\) の連続区間を 1 つ選び、その区間を平均値で一斉に置き換えた後の「最大気温」を最小化する問題です。全ての選び方 \(l\) について操作後の最大値を高速に求め、最小を取ります。
考察
操作で変わるのは選んだ区間 \([l,\,l+K-1]\) のみで、そこは全て同じ値(平均)になります。よって操作後の最大値は
- 区間内:平均値 \(\displaystyle \text{avg}(l)=\frac{F_l+\cdots+F_{l+K-1}}{K}\)
- 区間外:元の値のままなので、区間外の最大値
の大きい方です。つまり [ \max_i F’i \;=\; \max\Bigl(\text{avg}(l),\;\max{i \notin [l,l+K-1]} F_i\Bigr) ] となります。
素朴な方法がダメな理由
各 \(l\) について - 区間和を毎回 \(O(K)\) で計算し、 - さらに区間外の最大を毎回 \(O(N)\) で探す
のようにやると、最悪で \(O(N^2)\) になり、\(N\le 10^6\) では確実に TLE です。
どう解決するか
- 区間の平均:スライディングウィンドウで区間和を更新すれば、各 \(l\) あたり \(O(1)\)
- 区間外の最大:前計算で「左側の最大」「右側の最大」を作れば、各 \(l\) あたり \(O(1)\)
これで全体 \(O(N)\) にできます。
アルゴリズム
- 配列 \(F\) を読む。同時に最初の区間(\(l=1\))の和 \(ws=F_1+\cdots+F_K\) を作る。
- prefix 最大を作る:
[ \text{pre}[i] = \max(F_1,\dots,F_i)\quad (i=1..N),\;\text{pre}[0]=- \infty ] これで「区間の左側(\(1..l-1\))の最大」は \(\text{pre}[l-1]\) で取れます(コードでは 0-index の都合で \(\text{pre}[l]\) を使用)。 - suffix 最大を作る:
[ \text{suf}[i] = \max(F_i,\dots,F_N)\quad (i=1..N),\;\text{suf}[N+1]=-\infty ] これで「区間の右側(\(l+K..N\))の最大」は \(\text{suf}[l+K]\) で取れます(コードは 0-index)。 - 各 \(l\)(0-index で \(l=0..N-K\))について:
- 平均 \(\text{avg} = ws / K\)
- 区間外最大 \(m_{\text{out}} = \max(\text{pre}[l],\;\text{suf}[l+K])\)
- 操作後の最大値は \(\max(\text{avg},\;m_{\text{out}})\)
- その最小値を更新
- 次の \(l\) のためにスライディング更新:
[ ws \leftarrow ws + F_{l+K} - F_l ]
- 求めた最小値を実数として出力する。
具体例(考え方)
\(F=[1,10,2,8,4],\;K=3\) とすると、
- \(l=1\) の区間は \([1,10,2]\)、平均は \(13/3\approx4.33\)、区間外は \([8,4]\) で最大 \(8\)
→ 操作後最大は \(\max(4.33,8)=8\)
- \(l=2\) の区間は \([10,2,8]\)、平均は \(20/3\approx6.67\)、区間外は \([1,4]\) で最大 \(4\)
→ 操作後最大は \(\max(6.67,4)=6.67\)
このように「平均」と「区間外最大」の最大を比較するだけで評価できます。
計算量
- 時間計算量: \(O(N)\)(prefix/suffix 作成が \(O(N)\)、全ての \(l\) の走査も \(O(N)\))
- 空間計算量: \(O(N)\)(\(F\), prefix, suffix を保持)
実装のポイント
区間外最大の取り方:区間が \([l,\,l+K-1]\) のとき、外側は「左:\([0,l-1]\)」「右:\([l+K,N-1]\)」。それぞれを prefix/suffix から \(O(1)\) で取ります。
平均は実数なので
ws / float(K)として計算します(切り捨て不要)。\(N=10^6\) と大きいので、Python では 高速入力(
sys.stdin.buffer.read())やarray('q')(64bit 整数)を使うと安定します。ソースコード
import sys
from array import array
def main():
data = sys.stdin.buffer.read()
ndata = len(data)
idx = 0
def next_int():
nonlocal idx
while idx < ndata and data[idx] <= 32:
idx += 1
sign = 1
if data[idx] == 45: # '-'
sign = -1
idx += 1
num = 0
while idx < ndata and data[idx] > 32:
num = num * 10 + (data[idx] - 48)
idx += 1
return sign * num
N = next_int()
K = next_int()
F = array('q')
appendF = F.append
ws = 0
for i in range(N):
x = next_int()
appendF(x)
if i < K:
ws += x
NEG_INF = -(1 << 60)
pre = array('q')
pre_append = pre.append
pre_append(NEG_INF)
m = NEG_INF
for x in F:
if x > m:
m = x
pre_append(m)
suf = array('q', [NEG_INF]) * (N + 1)
m = NEG_INF
for i in range(N - 1, -1, -1):
x = F[i]
if x > m:
m = x
suf[i] = m
suf[N] = NEG_INF
best = float('inf')
Kf = float(K)
NK = N - K
for l in range(NK + 1):
avg = ws / Kf
mout = pre[l]
rmax = suf[l + K]
if rmax > mout:
mout = rmax
val = float(mout) if mout > avg else avg
if val < best:
best = val
if l < NK:
ws += F[l + K] - F[l]
sys.stdout.write(f"{best:.10f}\n")
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。
posted:
last update: