Resubmitのため0ptは回避したけどレート減。
http://community.topcoder.com/stat?c=problem_statement&pm=13912
問題
2人がN枚ずつカードを持っており、各カードの数値は1~100の整数のいずれかである。
同じ数値のカードが複数枚あっても良い。
この2人で、カードを番号昇順に積み上げるゲームを行う。
ゲーム開始時、先手はN枚のうち一部、後手はN枚全部からスタートする。
2人は交互に1枚ずつカードを処理する。
どちらかの手番で、手持ち0枚の状態で番が回ってきたらゲーム終了
自分の手番では、次のいずれかの手を取れる。
- カードの山が0枚の場合、手持ちのカードを1枚場において山を作る。
- カードの山が1枚以上の場合、手持ちのカードのうち山の最上位の数値より大きな数値のカードを山の最上位に置く。
- 任意の1枚を破棄する。
2人が協力して山に積まれたカード枚数を最大化するとき、何枚積めるか。
解法
まず先手がN枚のうち一部から進める理由はない。
先手がx枚の場合後手の手番もx回しか来ないが、このゲームではあえて全体の手番を減らす理由はないので、先手もN枚使い切ると考えて良い。
あとは簡単なDPで、dp[最上位の数] := 最大枚数 という状態をNターン更新するだけ。
両者の手番では、
- 何もしない
- 最上位の数より大きな最小値のカードを山に積む
のどちらかを行えばよい。
class YetAnotherCardGame { public: int maxCards(vector <int> petr, vector <int> snuke) { int N=petr.size(),i,x,y,z; sort(petr.begin(),petr.end()); sort(snuke.begin(),snuke.end()); int dp[101]={}; FOR(i,N) { for(x=100;x>=0;x--) { FOR(z,N) if(petr[z]>x) break; if(z<N) dp[petr[z]]=max(dp[petr[z]],dp[x]+1); } for(x=100;x>=0;x--) { FOR(z,N) if(snuke[z]>x) break; if(z<N) dp[snuke[z]]=max(dp[snuke[z]],dp[x]+1); } } return *max_element(dp,dp+101); } }
まとめ
先手がN枚以下でスタートしても良い、という問題文に騙され無駄に考え込んでしまった。