Official

D - Draw Your Cards Editorial by physics0523


この問題では、以下の操作ができるデータ構造を使うと解くことができます。

  • 要素として値 \(X\) を追加 / 削除する。
  • \(X\) より大きい要素であって、最小のものを見つける。

例えば、 C++ では set というデータ構造を使うことができます。

今回は、以下の情報を保持しながらカードを処理していく方針を示します。
\(under_i\)\(i\) の直下に(表向きに)置かれたカード
\(pile_i\)\(i\) が下から何枚目に積まれたか (= \(i\) が表向きで見えている時、その山にはカードが何枚積まれているか)

以下の手順でカードを順に処理していけばよいです。

  • データ構造には、表向きで場に見えているカードの情報を格納するものとする。
  • 場の中(データ構造)から、表向きに見えている \(X\) より大きいカードであって最小のものを探す。
  • そのようなカードがあれば(このカードを \(Y\) とする)、以下の操作を行う。
    • \(under_X=Y\) とする。
    • \(pile_X=pile_Y+1\) とする。
    • データ構造から \(Y\) を削除し、 \(X\) を追加する。
  • そのようなカードがなければ、カード \(X\) を何にも重ねずに出すため、以下の操作を行う。
    • \(pile_X=1\) とする。
    • ( \(under_X\) は何にしていてもよい。)
    • データ構造に \(X\) を追加する。
  • もし \(pile_X=K\) であれば、その山にはカードが \(K\) 枚積み上げられていることになるため、その山を食べることになる。以下の手順で食べれば良い。
    • まず、カード \(X\) を含んだ山は今から食べるので、データ構造から \(X\) を削除する。
    • その後、カード \(X\) を食べる。すると、カード \(under_X\) が表向きになって出てくるので、 \(X \leftarrow under_X\) としてカードを \(K\) 枚食べるまで繰り返す。
  • 以上の手順を、山札が無くなるまで繰り返す。

実装例(C++):

#include<bits/stdc++.h>

using namespace std;

int main(){
  int n,k;
  cin >> n >> k;
  vector<int> under(n+5,-1);
  vector<int> pile(n+5,0);
  set<int> st;
  vector<int> res(n+5,-1);
  for(int i=1;i<=n;i++){
    int p;
    cin >> p;
    auto it=st.upper_bound(p);
    if(it==st.end()){
      pile[p]=1;
      st.insert(p);
    }
    else{
      under[p]=(*it);
      pile[p]=pile[(*it)]+1;
      st.erase(it);
      st.insert(p);
    }
    
    if(pile[p]==k){
      st.erase(p);
      int x=p;
      for(int j=0;j<k;j++){
        res[x]=i;
        x=under[x];
      }
    }
  }

  for(int i=1;i<=n;i++){cout << res[i] << "\n";}
  return 0;
}

posted:
last update: