Problem
Solution
题意为,Alice和bob玩一个游戏,给定一个数字N,每个人从(0,N)这个区间选出一个能被N整除的因子x(N%x==0),然后N替换为N-x,换对手重复这个过程,若谁无法重复这个过程了谁就输了。alice先手。
这道题我最初的做法就是手动列了前9次游戏的可能性,发现如果初始的N是偶数,就是alice赢,初始的N是奇数,就是bob赢。
class Solution {
public:
bool divisorGame(int N) {
return N&1?false:true;
}
};
一开始就找了个规律,也没有严格证明。
其实这么想
假设如果到了某一步,轮到Alice下,还没变换的N是奇数
那么有一个结论:这个N经过这步变换后不可能还是奇数
证明:若N是奇数,x是N的一个因子且N-x要为奇数,那么x一定是偶数,那么N至少要有2这个因子,与N是奇数矛盾
那么这一步下完之后alice把N变成了一个偶数,Bob需要处理这个局面
Bob可以减去1,继续保持N为一个奇数的状况,重复上述,alice只能继续把N变成偶数 …
那么当N一直缩小至1(这一步必定是bob来操作,因为bob用最优决策下,Alice处理完后N一定是偶数)
N=1,Alice无法操作,bob就赢了
上述假设把Alice换成bob,bob换成alice同样成立
因此,初始N为偶,alice赢,否则bob赢
证毕
线性Dp做法:
对于每个初始的N,找出所有因子x,若dp[N-x]==false,那证明Alice可以取x做第一步操作,且给bob留下了一个必输的局面,因此alice必赢,若对于所有x,Alice都无法赢,则bob赢。
class Solution {
public:
bool divisorGame(int N) {
vector<bool> dp(N+1,false);
for(int i=2;i<=N;++i){
for(int j=1;j<i;++j){
if(i%j==0&&dp[i-j]==false){
dp[i]=true;break;
}
}
}
return dp[N];
}
};