E - K-Divisible Subarrays Editorial
by
ngtkana
Editorial for printing
DP に帰着する
接頭辞 \(A _ 1, \dots, A _ i\) に対する答えを \(\mathtt{dp}[i]\) とし、これを DP で計算します。
公式解説同様、\(A\) の \(\bmod K\) 累積和を \(S _ 0, S _ 1, \dots, S _ N\) と置きましょう。また、各 \(i \in [0, N]\) に対して、\(b_i = \# \left \{ j \in [0, i) \mid S _ j = S _ i \right \}\) とおきます。これは前計算してもよいですし、逐次計算もできます。これらを用いると、\(\mathtt{dp}\) の漸化式が次のように書けます。
\[ \mathtt{dp}[j + 1] = \max \left ( \mathtt{dp}[j], \max \left \{ \mathtt{dp}[i] - b_i + b_j \ \middle | \ 0 \le i \lt j, \ S _ i = S _ j \right \} \right) \]
DP を効率的に計算する
これの計算のためには、各 \(x \in [0, K]\) に対して \(\max\left\{ \mathtt{dp}[i] - f(i) \ \middle | \ S_i = x\right\}\) (実装例の Value::max) を追加で管理すればよいです。またこれさえ管理すればもう \(\mathtt{dp}\) 本体は明示的に管理せず、現在の値 \(\mathtt{dp}[i]\) (実装例の ans) だけを管理すればよくなります。
実装例:
短いですね。
use proconio::input;
use std::collections::HashMap;
fn main() {
input! {
n: usize,
k: usize,
a: [usize; n],
}
let mut hist = HashMap::new();
hist.insert(0, Value { count: 1, max: 0 });
let mut sum = 0;
let mut ans = 0;
for &a in &a {
sum = (sum + a) % k;
let e = hist.entry(sum).or_insert_with(Value::default);
ans = ans.max(e.count + e.max);
e.max = e.max.max(ans - e.count);
e.count += 1;
}
println!("{ans}");
}
#[derive(Default)]
struct Value {
count: usize,
max: usize,
}
posted:
last update:
