SRM 360 Div2 Hard TakeSubstringGame
問題
与えられた数nに対して二人が次のようなゲームする。
- nの、部分文字列であるような「正しい数」を選ぶ。
- nから正の「正しい数」を引く。
- その数を新たなnとして、相手のプレイヤーが同様のことを行う。
- 正しい数を取れなくなったプレイヤーの負けである。
お互いが最善を尽くすとき、先手が勝つならば、先手の選ぶべき数を(複数ある場合、最も小さいもの)返し、後手が勝つならば-1を返せ。
ただし、正しい数とは、先頭に0が来ず、なおかつ元の数自体になっていないような部分文字列を言う。
制約条件
n≦10^6
方針
メモ化再帰して探索すれば解ける。特に工夫は必要ない。
rec(n)は、nでゲームを始めたときに、先手が選ぶべき数を返す。
先手必敗の場合はinfを返す。
ソースコード
int dp[1000001]; int rec(int n){ if(dp[n]!=-1)return dp[n]; dp[n]=inf; int d[9],nd=0; for(int m=n;m;m/=10)d[nd++]=m%10; rep(i,nd)for(int j=i;j<nd;j++)if(d[j]!=0&&!(i==0&&j==nd-1)){ //leading zeroが来ない、かつ、全体になっていないものが選択肢 int m=0; for(int k=j;k>=i;k--)m*=10,m+=d[k]; if(rec(n-m)==inf)dp[n]=min(dp[n],m); } return dp[n]; } class TakeSubstringGame { public: int winningMove(int n) { rep(i,n+1)dp[i]=-1; int ans=rec(n); return ans==inf?-1:ans; } };