题目大意:
n*20的棋盘,每行有若干个棋子。对于一个棋子,能将它向右移动一格,如果右边有棋子,则向右跳到第一个空格,如果右边没有空格,则不能移动这个棋子,如果所有棋子都不能移动,那么将输掉这场比赛。
解题思路:
根据题意可知每行进行操作都是独立的,所以整个游戏又可分为n个子游戏,这是sg定理的第一步。
下一步考虑每个子游戏的状态。可知当棋子紧邻着排在左边的时候为必败态,而其他状态的后继可以通过枚举每个棋子向右走一步得到。这样通过sg解题就差最后一步如何表示状态了,每行只有20个固定的格子,每个格子只有有无棋子两种状态,于是就可以直接上二进制压缩了。
代码:
//bug1:递归过程中使用stl爆栈导致tle
//bug2:递归参数使用全局数组导致数值紊乱wa
//bug3:寻找mex值时未考虑后继状态sg值会重复导致wa
//bug4:忽略else会和最临近的if对应导致结构错误
//以上bug已全部修复
#include <bits/stdc++.h>
#define int long long
#define BS 1048576
using namespace std;
int sg[2000005];
int dfs(int x)
{
if(sg[x]!=-1) return sg[x];
int a[25],cnt=0;
memset(a,-1,sizeof(a));
//从右到左第i个位置
for(int i=1;i<=20;i++)
{
int next=x; //next代表后继状态
if(((x>>(i-1))&1)){
//如果第i个位置为1
next^=(1