geam1113’s diary

主にAtcoderのコンテストの備忘録を書きます。AtCoder緑と水色を行ったり来たりしています。

AtCoder Beginner Contest 281 参加記録

コンテストページ: https://atcoder.jp/contests/abc281
コンテスト中AC: A〜D
コンテスト後にEをAC(自力)

D - Max Multiple

  • N,K,Dが小さい
  • 倍数はmodの情報があれば良い

これらからDPだろうと判断しました。
情報としては、

  • 何項目までを考慮したか
  • 選んだ項の総和のmod\ D
  • 選んだ項の個数

が分かればよいので、

dp[i][j][k]:=Ai項目までを考慮し、選んだ項の総和のmod\ Djであり、選んだ項の個数がkであるときの選んだ項の総和の最大値

遷移は以下のとおりです。

  • A_{i+1}を選ばない場合
    dp[i+1][j][k]\leftarrow max(dp[i+1][j][k], dp[i][j][k])

  • A_{i+1}を選ぶ場合
    dp[i+1][(j+A_i)\ mod\ D][k+1]\leftarrow max(dp[i][(j+A_i)\ mod\ D][k+1], dp[i][j][k]+A_i)

初期値は、dp[0][0][0]\leftarrow 0としておき、その他は-1などで埋めておけばよいです。

なお、dp[i][j][k]-1の場合は遷移元としないようにする必要があることに注意します。

答えは、dp[N][0][K]です。

提出コード: Submission #37160568 - AtCoder Beginner Contest 281

E - Least Elements

コンテスト中multisetで解こうとして結局だめでした。コンテスト後にWavelet Matrixで解けました。

A_{i-M+1}からA_iまでを昇順に並べた数列をB_iとします。B_iの先頭K項の和をS_iとします。

i=M+1,M+2,\cdots ,Nについて、A_{i-M}を削除し、A_iを追加した場合に、B_{i-1}からB_iにどのように変化したかがわかれば、S_{i-1}から変化分を増減させることで、S_iを計算できます。

これを考える時、A_{i-M},A_iがそれぞれB_{i-1},B_iK番目以内かそうでないかの4通りを考えれば良いです。

具体的に説明します。

  • A_{i-M}B_{i-1}K番目以内
    この時、A_{i-M}の分、和は減少します。

    • A_{i}B_iK番目以内
      A_{i-M}が削除され、A_iが挿入することを考えると、削除されて空いた箇所に左詰めまたは右詰めで各要素が移動し、A_iが挿入されたと考えることができます。
      このケースでは、新たにA_iK番目以内となってその分の和が増加するので、
      S_i \leftarrow S_{i-1}-A_{i-M}+A_i
      と計算できます。

    • A_{i}B_iK番目より後ろ
      A_{i-M}が削除されて空いた箇所にそれより後ろの要素が左詰めされて、A_iが挿入されます。
      このケースでは、B_{i-1}におけるK+1番目の要素がB_iで新たにK番目となり、この分の和が増加するので、これをB_{i,K+1}とおけば、
      S_i \leftarrow S_{i-1}-A_{i-M}+B_{i,K+1}
      と計算できます。

  • A_{i-M}B_{i-1}K番目より後ろ
    このケースでは、A_{i-M}による和の減少はありません。

    • A_{i}B_iK番目以内
      A_iが挿入されると、A_{i-M}の削除によって空いた箇所に右詰めされるように動きます。 このケースでは、新たにA_iK番目以内となってその分の和が増加し、B_{i-1}K番目だった要素がB_iにおけるK+1番目となって、この分が減少するので、
      S_i \leftarrow S_{i-1}+A_i-B_{i-1,K}
      と計算できます。

    • A_{i}B_iK番目より後ろ
      A_iは和に影響しないので、 S_i \leftarrow S_{i-1}
      となります。

B_iを全て記録することはN^2の領域が必要となるので、不可能だと思います。また、仮にそれが可能だとしても、C++vectorなら昇順ソートが毎回必要ですし、multisetでは何番目の要素かを得るのに時間がかかります。

そこで、Wavelet Matrixを使います。Wavelet MatrixはO(NlogA_{max})で構築し、O(logA_{max})で指定区間の任意のx番目に小さい要素を得ることが可能です。(但し、A_{max}Aに含まれる要素の最大値)
これで、O(NlogA_{max}+QlogA_{max})で解くことができます。

実装: Submission #37188154 - AtCoder Beginner Contest 281