問題
http://community.topcoder.com/stat?c=problem_statement&pm=12496&rd=15495
2人でのゲーム。
ある数が与えられ、プレイヤーは1とその数自身以外の約数をそこから引くことができる。
約数を引いたら、次のプレイヤーに交替して進めていく。
このとき、ある数が与えられたときに最初のプレイヤーが勝つなら”John”、
負けるなら”Brus”を返す。
解き方
与えられる数の最大は10^18のため、dpでは解くことができない。
そのため、法則がないか見つける。
とりあえず「適当な数までサンプル出力し、法則をながめる」ことが1つの手法。
法則は以下の通り。
1)2^n以外の偶数が与えられたら勝ち
この場合、x=2y*2z=2(y+z)、
(ただしy+zは2^nではない、つまり奇数の約数を含む)
で表わすことができる。
このとき、偶数と奇数の約数が必ず存在するので勝ちとなる。
2)奇数が与えられたら負け
奇数は「素数」もしくは「奇数で割る」ことができる。
奇数で割れるときは、奇数ー奇数のため必ず偶数になる。
このとき、2^nを含んでいるとすると奇数はx=2^n+yと表わせるが
2^nの倍数で割れないため、2^nの偶数ではない。
つまり、奇数を引いたときは2^n以外の偶数が現れる。
2^n以外の偶数は必ず約数が存在して、
一方奇数で割ることができなければ負けとなるためこの場合は負けとなる。
3)2^nの偶数のとき
たとえば2^3=8のときは、2,4で割ることができる。
2^1を引くと6となり2^n以外の偶数が出るので負けとなる。
そのため、2^nが与えられた時は2^(n-1)を引くしかないが
その結果が2、つまりnが偶数のときは勝ちとなるが
奇数のときは負けとなる。
コード
class TheNumberGameDivOne {
public: string find(long long n) {
int num=0;
if(n%2)return "Brus";
while(n%2==0){
n/=2;
num=(num+1)%2;
}
if(n!=1)return "John";
if(num)return "Brus";
return "John";
}
};
public: string find(long long n) {
int num=0;
if(n%2)return "Brus";
while(n%2==0){
n/=2;
num=(num+1)%2;
}
if(n!=1)return "John";
if(num)return "Brus";
return "John";
}
};