めちゃくちゃ苦労したけど、コンテスト外でやっと解けたので記録してくおく。
最初に考えたこと。
差分計算したい。
更新時に未使用の色のうち、インデックスが一番小さいものを採用すればよさそう。
ある色が採用されたとき、いくつのボールが利用されるかは事前計算しておく。
色をインデックスとしたセグ木に、各色の一番小さいインデックスをいれて更新していく。使用中の色にはInfを入れておく。
この方針はだいたいのケースでうまくいくんだけど、考慮漏れがあって、一つの色が複数の箱に入る場合にWAになる。
そこでさらに発展させて、箱が無限にあったとき、各色が何個の箱に入ることができるかと、n箱目では何個のボールが入っているかを事前に計算しておくことで、いい感じにセグ木の更新と求める合計を計算することができる。
と書くのは簡単だけど、実装は結構大変だった。コンテスト時間ないに解くのは今のところ絶望的。
擬似的な説明を書く。
各色のボールがn箱目で利用されたときの利用されるボールの数(最大K):ball[color][n]
各色のボールのindexを管理する配列(予めCを2周分にしておく)。各色の左からt番目。存在しないときはInfを返す。 : index[color][t]
各色について未使用のボールのうち最も左のindexを管理するセグ木。存在しないときはinfをいれる。: segtree[color]
各色について何箱利用しているか : count[color]
初期状態の答え: sum
ballはpop()で先頭を消せるようにリバースしておく。
for _ in 0..M{
}
let mut ans=vec![sum];
for i in 0..N-1{
let preColor = C[i];
count[preColor]-=1;
index[preColor].pop();
sum-=ball[preColor][count[preColor]];
segtree.update(preColor, index[preColor].last());
let j = segtree.all_prod();
let nextColor = C[j];
sum+=ball[nextColor][count[nextColor]];
count[nextColor]+=1;
let L= index[nextColor].len();
let n = index[nextColor][L - count[nextColor]*K -1];
segtree.update(nextColor, n);
ans.push(sum);
}
以上を実装してAC。