题目链接:P4101 人人尽说江南好
算法分析
无论怎么操作,最终合并的次数为奇数,则先手胜,否则先手败。先假设一种合并方案,双方尽量合并成 m m m,然后再从1开始合并。这样总共的合并次数为: c n t = n / m ∗ ( m − 1 ) + ( ( n % m ) ? ( n % m − 1 ) : 0 ) cnt = n/m*(m-1)+((n \% m)?(n\% m-1):0) cnt=n/m∗(m−1)+((n%m)?(n%m−1):0)。我们称此为套路。
如果此时cnt为奇数,我们知道先手胜。先手必胜,肯定会按照套路走,如果后手不按照套路出牌呢?讨论下:
最大堆石子数 < = m − 2 <=m-2 <=m−2
-
后手将1和最大堆合并,这是按照套路走的,先手继续按照套路走即可。
-
后手将两个1合并,得到一个为2的堆,先手将这个为2的堆和最大堆合并,将后手的思路拉回到套路上来。
最大堆石子数等于 m − 1 m-1 m−1
-
后手将1和最大堆合并,没有区别。
-
后手合并两个1,得到一个为2的堆,先手将1合并到最大堆,此时最大堆已满。后面又可以按照套路来了。
无论怎么操作,先手都可以稳住套路,保证最后的合并次数不变。
后手胜的情况也是一样的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long
ll n, m, cnt;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%lld%lld", &n, &m);
cnt = n / m * (m - 1) + ((n % m) ? (n % m - 1) : 0); // ?:运算符得用括号,否则错
if (cnt & 1) printf("0\n"); else printf("1\n");
}
return 0;
}
反思与总结
-
在用条件运算符时,整体得加括号,否则错误。
-
该题思路:确定一种方案,证明其他方案最终和该方案等效。